我正在尝试使用azure-sdk-for-node将流式图像保存到Windows Azure blob存储,但没有成功。下面是我调用的函数,并使用缩略图属性传递视频对象。最初我使用请求对象获取图像,该对象从另一个网站获取图像并将其转换为base64对象,而base64对象又转换为流对象,因为Azure blob服务使用createBlockBlobFromStream方法,因为我无法使用createBlockBlobFromFile或createBlockBlobFromText将图像上传到blob存储。
var azure = require('azure')
, uuid = require('node-uuid')
, http = require('http')
, url = require('url')
, mmm = require('mmmagic')
, Magic = mmm.Magic
, stream = require('stream');
function createVideoThumbnail(video, callback){
var bs = azure.createBlobService(config.storageAccount, config.storageAccessKey, config.blobHost);
var sURL = video.Thumbnail;
var oURL = url.parse(sURL);
var client = http.createClient(80, oURL.hostname);
var request = client.request('GET', oURL.pathname, {'host': oURL.hostname});
request.end();
request.on('response', function (response) {
var type = response.headers["content-type"];
var prefix = "data:" + type + ";base64,";
var body = "";
response.setEncoding('binary');
response.on('end', function () {
var base64 = new Buffer(body, 'binary').toString('base64');
var data = prefix + base64;
console.log('base64 image data ' + video.Thumbnail + ': ' + data + '\n');
var decodedImage = new Buffer(data, 'base64');
var magic = new Magic(mmm.MAGIC_MIME_TYPE);
magic.detect(decodedImage, function(err, result) {
if(err) {
throw err;
}
var bytes = 0;
var imageStream = new stream.Stream();
imageStream.writable = true;
imageStream.write = function(buf) {
bytes += buf.length;
imageStream.emit('data', buf);
};
imageStream.end = function(buf) {
//if(arguments.length) {
imageStream.write(buf);
//}
imageStream.writable = false;
imageStream.emit('end');
console.log(bytes + ' bytes written');
};
var options = {}
console.log('mmm = ' + result + '\n');
options.contentType = result;
options.contentTypeHeader = result;
console.log('\n');
bs.createBlockBlobFromStream(config.imageContainer, uuid().replace(/-/gi, "").toLowerCase() + '.jpg', imageStream, decodedImage.length, options, function(error, blobResult, response) {
if (error)
console.log('got error = ' + JSON.stringify(error) + '\n');
if (blobResult)
console.log('blobResult = ' + JSON.stringify(blobResult) + '\n');
if (response)
console.log('response = ' + JSON.stringify(response) + '\n');
// now store in Azure blob storage
callback();
});
imageStream.end(decodedImage);
});
});
response.on('data', function (chunk) {
if (response.statusCode == 200) body += chunk;
});
});
}
这就是我所说的:
createVideoThumbnail(video, function(){
console.log("returning from create thumbnails\n\n");
});
该功能无法正常工作,无法打印出最终的日志声明:
console.log("returning from create thumbnails\n\n");
然而,base64确实可以工作,因为我得到了这个编码:
数据:图像/ JPEG; BASE64,/ 9J / 4AAQSkZJRgABAQAAAQABAAD / 2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7 / 2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7 / wAARCABaAKADASIAAhEBAxEB / 8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL / 8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4 + Tl5ufo6erx8vP09fb3 + PN6 / 8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL / 8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3 + PN6 / 9oADAMBAAIRAxEAPwDx3QNShMv2IyqFcFrVieGHdCfUVFqDrY3BKsVU9favMba7uJn + XcoB3Lg42n1FbWdZu0G6eSQnjLLnNVLFJaMiOElLVGuNTZL8Wkaw7N + 4llzmrtjek35RFtwCrdI8g8fWub13w34r03S11m 502V7Fh81xECVj6fexyv1PBpng2R5rg3EsmFijYn3JGAKqNXm1uOpT0s + hZsLtzrN / AfuTHgKMAMvTiqEtlJLqoEQJVvm4 / UUljeIJrwjiQlsHuOat6TPcazcrbWdrJNqCZ2RxxlvM9xirdrIhxcbNEWtWVw9nMvlP8o3HI9K5GvZLT4d + PbxEmfwzdhGwfnkRTj3BbNeZeJ / d + raBqMlvqmmXVkC7eX50ZUOoPVT0P4Vk5Rlsy4ppamRSqCzADqakji3ruMiL9SasWNuxuk3EbTk7l5pWHc29LiARFHQCuv0R2DooGQpBzjpXKW8bpt8srIP9k5 / Sty1vV0yxe9kwZUGIlPRnPTPt3 / Ct4WMJamlqogfxG1yFCvDEsLYORu6nj8QPwq9G7vcrbgZc4LDvnHTNYXh0R3HEzqJvvmQniRie9a0tzHYpNfuwBjGAc5JJrVfzC5erPfvhtqDXng20aU7mhLQ / QKSAPyxXRs + V4GOa89 + BRnbwGstwMvNdSSH26cfpXcSTeWhLfhXyOJi3Xko92elD4ESsy4JPFVp2DLzziqr3UgZjj5fSljlEgY5wfSlKhOmrtFpor3tvBOpWeCORcfxLmuQkULvITyFGQWL9B2NdfeORDIwIyFNcdIQ8IB2kgfxdCfpWlDszopSqJe7sV / d / AMHfDaaxPctHKluW3R20r52e3Bzj0zXomn + BPDEAj / 0KJ1TlRjgVtC2i1KNbq3G2VT6Yz7VoW4iChcHI7HiscZKfPzdGenSoRpxUexFDZWSQ / Z4rdBEQVKbRtIPBBHcYrxv4mfAi0vbp9T8FTRaTcyHMtm + RbPnuuATGfYAj2Fe6w + Vn7q / nTnZS3QflWNDE1KL91mVfDQq7o + YPB37POszaiZfEmoW1raH7yWrF5W9skAD68 / SvffB /克/ QfC1mLXQtLhtVwN8gXMkh9WY8mujVgDgA / lUgO4dM / jW1XG1ays3ZeRlTwtOn5sgeBivJrE8S + F9K8Ra XNpusWkV1bSjBVxnHoQeoPuOR2rpApPGAKBC7MMdPpWMKkoO6ZpOCmuWR8E / FjwXdeA / FMumN + 8s5CXtZHXJZPQn1H + B71z2juDO29EB28MK + sv2vfC6XngCHXFj / f2E6kvjojEKR + JK / 9818jRhre6WRY2WNxwccfh + NfSYar7WCkzwq9L2cnE6KAL5oYjBHOR1qr4mu5bueC2RGZgOUiXlmP / wBbFSxzIliZ5flUDPI6gf4n + tYSXj / aUnIc7iS + 1sHk9j2rs2RzxXU2rWcWSCS / DQ6 / 6u2Vu / QX / pXS6HbT3dsdX1VG + wwHesR4Nw5OBx + gFc7o + q6dbT + dHokV3L2V1aRgfUsTj9K7HSLvxT4nkltdLSNJ4YjKbeO281o1BxuGDwfqB1qotJ3YJSlJWR698H7maPw9LbtEok88yvGrgCMMBgfpXV3M8kqx74mjOMshIJH4ivMPgxa / 2Nrl / YajNdR6nPCkhiulZGkUE / MoPYc9K9QuoxKd4wWHb1rwq7jDFNvY7KWkLNEDPyxPJPaolm2ENkfypwiuGyI4JSD2VT / Sll0rUxtMtjcRJ / eeMqPzIrpla2o0Q6jLts5SD1U8g5rk9xYcL35rodR0m4uWWztJ7VLyZgkULX8asxJ6BC3JP0rznVvEcMGVtVW5mVirLuCqT0wScfpXHSou2x6OFqQhB6nuPhbVrWeKOS1l3hyOp6GurmsY5GEoJBYcgeteR2ULeG / EcSbAbO8yo / 2JANwx9QD + VelaLqAubffHJkp0XPJHp9a6FShVhzdDsjUcnbqX49qziDI8zbkL0Jx1xT5pUQZGPpmsC7abWb2Caykksb6yk3qs6 / K4wQQceoP8q56Hxjq0N / QZ + I7KKyNupeOKNlwEVSS2SeScVwVcLBaxNKnuxvck + IHxK8NeDWSPWLt3u5AGjtYF3ykeuDwo + pGe1c54Y + PXgrWNSSwuGvtJd3xHLdRr5WT6sGO38cAeor5v13WJda8S3G q30kM93cTGRmKRtn0GMuMAYAHtUE2C5mijZVP39iYAP4RqB + ddccFFRs9zy / aucj9CNKimniDFGYEZVhzkfWrUr2cH + vvLSHb97zJ1XH1ya + aPAV / e6h4G0Vri8keRYtmZJSflWWVFXBf029q6 / wAEW1vqC6slzHG5 / s5JFLRhiu3AyOD / AD / OoWXQb1ZEsZKN9Dsfjc + h678N9S0eHXtINzPGDErXabWIYEfNnA5Ar5lsfhhr1xHHp0Ot6G0ZfzGt40lmlIIBG0rEeo9DXsEUkbfDV0C7JLe9AB + 6cFXPByp / HB / AVW8DaibHxlYXtzdtCi + UDK7cKPlUk5z2z3ruo01RioxOOrU9o25HlWo / Cm3vJAl34m + zRRoGCW + mu2en / PRO + X / nWl4e + CegvanU5b / V9TtYpEVxGIYQCzFRn53I5B7V1OpGSXWLtrNC8csf7sxKfmAGBjhT2rX0rxHbaR4R1TSdVuDbXdwIDAtywXBV2LZ3scdRyMV0Nyepg7JaGH4S + H / HW / 1SOy0zTNSiklYAyTagzZwGbqIcdhxkVc1DwrJBM2laRps1lqLIZJJYZJJJigcjOHlAKnAOQB14qfwJcS6N4is9TgFncGGZZUWK4jPmDPTcoyuVJr1XRteivTDe3ltEl / bboCd28SRnkJnABYADt6 + tTUqcsbM6cJSdSV4u1jnLjw5caN4fstcVbcXsTfZZXls45Jo4S + AC5WQ5Oc8H8K5CHxTrPnCL + 0rkcN80cqRjdtOPurGRziu18ZeO / DmjRrpuoyx3 + lTJny4gsjQMfuqfY44PUY57V5dpV / od8rXFkt9H85RhJc8ZPYDHI / E1zqpC12jXEYacXdSvc9F + KFjcaULS6ttSviLmBifMvLhz9zcDy7Dnn + nevM7F4ZNRQyNFOSr / ADNsZc7Tx8yA9fet / WdaSS0t / t1qblYB5cXm3EjFRjHAJI6Dtiq1pr2jOoj + yw24H / Tun8wM / nTeISWkWzOGDr SjdI73xpN4bs9e8P3mjyWrPDdxSOLVgQqAgkbVyOo746nr2 + cvHtvFZ + MdasTdsBDfzRjgE4V2A5r1PUtUNwqxWt0 / KY + 6jEKD9OlYd / Z2d3C0dzawzLk53KDzULFJvY6KWXyUbtnV / Gqe6i8OW17bSJE1teI4GOWPIH86b4U1a / XV1kjZ1e12faYyGVX3KG + 64BHBBBxg1p + O7XRrtNP / AOEgmMekwTPPcKCQZNsblVBHIyf8O9eJ6x4gFx4kH / CBWV1Zwz7Y385zK0m3d8zMegAOMA9hU4NpUNTWrVdPE2SPcPikNakfS / Enga7jFy77Lq0Z1AnXHBO4jpj9a4DTvEza54xutK8VTx2Wpzj7ObZPugbSMbhwSQSeteS6x4q8Qtq0pa4KTRysoCkgKR6c8VUtrXWL7UpL + ZpftOTLvdsElRng + vFOdNW8jtpyVd8kU7iavoer6P4w / wCEcv1nadJwkQyxDgn5WXnGDVWPTLy51I2sNnLNMz7AioCxOcYHB5r1zR / ibZb7JPGXheO / udPl321yMedGVOQT07gZ5HuKuXPxN8OWMss / hbwt5eoysW + 1XOMJnqVAJz3 / AIH + NEak76xM4YTkm01c0YNO1D4e + GtE026ihmvXtmnuY2mIEJ3lsHap45A9yDWV468X694K8O6de3Flapc6srCG3MjuPIXB3OwK9SwwuOnXHSucvNd1O / vWvtauZ / trEqrvzwOwHYc8dh26V7b8f /艾+ N / h3BNYx51PSojPaKg5kUqN8eO5IVSPdcd6Sqcs1GT3DMMFCjRjKC957nzTcfFnxYxAt / sFquSQkcG4c8Hhy2ep61nXfjXxleSeYdXuID / 0xZIMfQKB + VcrPG8UhRxgjiiON5CAvf3ruSR4DbO40PWrzWXFpq2tXMk6t9 + a4LFx9SeapeKPDUyTG9tZkeN + fvDqOtc19kxgtJt9zQ7XAHlx3Erp7EgVpfTVGVne6Z2nhfx1qWip9nnf + HCOeS jDoa9gsvEMNn8PbG1tdZme7uEN2lyzg + VMxJdT7ZJ / PPavmMqQ2HJHvW3omq3UdnJo4k329w6kA / wEHPH1rKpHnR2YbEOhfzPY / BHw28beOfMfT9PkNjK4L3M7iJDk9QW + 8B1 + UGuitNEGhiTTVgIMMjJI27JLLwWH5e1e0fCzUZ9P8HaVZpwY7ZBj8BXj + v6tcr4l1CQIzo1zJgDoQXPP1rlxEFCKHSxEqsncyvEEhKrGqp1yc8 + 3NYwZX4AG3HBz0q / Q + tWzTATR7TswdyYqC1e2uZR5JIBI4BztH40oaRPo8NaNJGjZsViRFDfKOe1SSOobbjB6mt6y8I3t7oy6jZ3NtHuyxR22ttGfw7etcvcyHKn + DdyRz71g4Pd9TGNWE21F7HovjbQm8Q6DJY71jfIeNj2Yf / rNZt / Z2nhjwhLcSxQRxWNtkADgtjH6n + ddekueNo / KQ + v6XHrWh3elzr8lxGVzjoeoP4EA15qntF7XKUFfm6nyDPby3l552GeSeTdn + Jizeg / HirlhpmqSaoLC1E0lwkm1PJy5J9AByT9K7m4 + GfjSPUltI9KaWFV2JIkw2cdDnPTnPrzXq / hPwxoPgDSJ9c1Iw21wsQa7u5HyE9VTvgnsOTwPSvVqYmKS5dW9kXKNGh7yf6Hm + mfBTxtd2Rlnjs7dpDuYS3BEnX0UEA4z + dYF74C8R6NqX9n39hJFPcP5duUXdvJP8DA459z35re8VftF6gmomPwxpdv9kjbHm3oLNL77QRtH4n8K2vCH7SOlzyxR + KdCe0YEZuLRvMQH12nkfgTU8uKSu0n5HPDN6anqrnaeBPg9bWq2N74luFuJYY122ifcQhi2Gf8Aj5PsPwr2B1SKFijKuwZBA6YritG + J3w / 1e1Wa28V6agIzsmlEbD6hsGuG + Mfxv8AD + i6NcWHhjUYdT1SZCiPAweOHP8AEWHHHp / SuBUa9WouZMjEY2NSLblc + bfiYtgPHWvW9jtW1h1C5W Hb0CB2wB + QrmrVyJEAO35uTio3d3dpHYsznLMeppAxC4HHOc19CtDwG7l0vFvJZt5zwAOtWFQyKGfj0Qf1rMjcIcqOfU1ILhh1dj9OKu5DRbntvl5ApmmxiPUoHdtqLKpY + gzzURvGIxjj60sd0M8jFIVmfdGg30FvpEc0UivEsAZHU5BG3II9q8haVI2d3bMjOWYFskZzjGKyfgp4ye88Mah4WnuAt1FbsbF25yp4K9RnaTnHpn0rRGl6qvH2iwb / ALd3X + T1zYmMp2SNMPJU73MW8EUkrGT58tyS2eO1NsbOIyB44yrjkbeCfr2rTm8Oag2T51mpP91G / qTSRaNrVu5aN7KUE5 + YsuP0NS4S5bJHurMKHLYctzexfuDI4TG04Y5Oe1RyTCIucdAoC + pJp8ljruSxgscnpiduv / fFQyabq5IZ7S3yDkkXB6 / 98 + 1YqlPqhRxlDe57jEcD7wFXI3G3O8VlxfdqUE7TzXiM60i5d6hZ2NnLeXl0kMES7ndjgCvnP4wa / f8Aj29WytZpYdNgcm3gUcu399x3Pt2H456n41Tzf2rY2 / nSeSYyxj3HbnPXHTNYXhZE2O + xd2cZxzXu4LDwhDn3bPCxmJlOTj0R4jq + l3mmX7WdzGfMHTbyD9KntNGnlUF1ZSe1egfGBVUWMiqFfzSNwGD0rJ0Il4fnJb6816EI3OHmdjEHhaVkDfaVX2K5pY / CzgkvchgPRcV04 + 8B2zT8Da1a + zRHOzlLnTIoIXEzqqDqSKwbpIY2AikZ / XcuMV3d0AdpIBNcx4gVfNLbRuwOcc1nJWLizIjjL5wDx6DNTC3T + KXB / vKRVvRe9akgG0cDvUpDb1MQWcbAbZUb6NSmxI9av3EcflqfLXOPSktOCQKdhXZBpVzd6RqUGoWbkSwOGX0PsfY9K + jvDmsQ6xpEGoW / 3JkztPVT3H4Gvn + RVx90flXpPwYZv7Kv03Has4IGeBlamSsDPRXmyQAnSlWQ / wB3FQ p941MOlSA / cG6jI96bNsIHAXA7d6cAM9BVS9JATBx8w6VQj //ž
mmm = application / octet-stream 5283字节写
但我没有收到任何这些日志声明:
if (error)
console.log('got error = ' + JSON.stringify(error) + '\n');
if (blobResult)
console.log('blobResult = ' + JSON.stringify(blobResult) + '\n');
if (response)
console.log('response = ' + JSON.stringify(response) + '\n');
所以我假设它挂在某处或者我没有正确构建我的代码。谁能看到我做错了什么?
干杯 罗布
我的消息来源:
Node.js base64 encode a downloaded image for use in data URI
答案 0 :(得分:0)
这是我的简化版。由于魔法需要对整个文件进行操作,因此使用流式博客API毫无意义,而是为文本api编写。 body
将是图像的缓冲区,我怀疑azure会对它进行编码感到满意,如果确实需要它,请调用toString('encoding')。
var azure = require('azure')
, uuid = require('node-uuid')
, request = require('request')
, mmm = require('mmmagic')
, Magic = mmm.Magic
, stream = require('stream')
, bs = azure.createBlobService(config.storageAccount, config.storageAccessKey, config.blobHost);
function createVideoThumbnail(video, callback){
var sURL = video.Thumbnail;
request(sURL, {encoding:null}, function (err, res, body) {
// encoding:null makes request return a buffer, which is ideal to run magic.detect on
magic.detect(body, function (err, res) {
console.log(res);
var container = config.imageContainer;
var blob = uuid().replace(/-/gi, "").toLowerCase() + '.jpg';
var text = body; //might need to be converted into a string, I don't have azure setup to test
var options = {
contentType: res,
contentTypeHeader: res
};
bs.createBlockBlobFromText(container, blob, text, options, function(error, blobResult, response) {
if (error)
console.log('got error =', error);
// if you give console.log multiple arguments, it will format each of them,
// no need to manipulate objects into strings manually
if (blobResult)
console.log('blobResult =', blobResult);
if (response)
console.log('response =', response);
// now store in Azure blob storage
callback();
});
});
});
}
编辑:临时文件版本
var azure = require('azure')
, uuid = require('node-uuid')
, request = require('request')
, mmm = require('mmmagic')
, Magic = mmm.Magic
, fs = require('fs')
, bs = azure.createBlobService(config.storageAccount, config.storageAccessKey, config.blobHost);
function createVideoThumbnail(video, callback){
var sURL = video.Thumbnail;
var name = uuid().replace(/-/gi, "").toLowerCase() + '.jpg';
var ws = fs.createWriteStream('./tmp/' + name);
request(sURL, {encoding:null})
.pipe(ws).on('close', function () {
console.log('downloaded');
magic.detectFile('./tmp/' + name, function (err, res) {
var container = config.imageContainer;
var blob = uuid().replace(/-/gi, "").toLowerCase() + '.jpg';
var options = {
contentType: res,
contentTypeHeader: res
};
bs.createBlockBlobFromFile(container, name, './tmp/' + name, function (err) {
callback();
});
});
});
}
答案 1 :(得分:0)
感谢msdn论坛上的Valery Jacobs能够得出答案。使用stream,request和util对象是一个很好的干净可靠的解决方案。
:)