我需要从供应商的Web服务中检索文件,并将它们推送到唯一的blob容器中,以便用户拥有唯一的“工作区”。本质上,我将从供应商处获取文件,并且用户可以通过自己的Blob容器中的文件进行编辑,以免彼此交叉工作文件。我有唯一的blob容器,但需要从供应商的API中“下载” /获取文件,并将其推送到blob容器中。我能够成功检索文件,这将是分别获取PDF,文本文件和图像的调用……但是,如果尝试将它们上传到Azure Blob存储,则在Node.js中会出现以下错误:
TypeError:无法读取null的属性“ length”
我认为我需要在客户端将文件编码为base64才能正确获取长度,并且已经看到了一些使用具有toDataURL的Canvas的示例,但是不确定这是否是从本质上直接下载并推送至的最佳方法。 Azure Blob存储,尤其是因为我有PDF之类的文件(不确定PDF是否可以使用base64编码)。
这是调用服务的我的AngularJS控制器(请注意,实际端点可能会根据调用的文件而有所不同,因此我正在使用文件的客户端GET来控制用户可以以表格形式输入的变量):
$scope.getFiles = function () { $.ajax({ url: 'http://vendorwebservice.net/ws/file1', type: "GET", success: function (result) { console.log(result); var filename = 'Texture_0.png'; $http.post('/postFile', { filename: filename, file: result }).success(function (data) { console.log(data); }, function (err) { console.log(err); }); alert("Files Retrieved!"); }, error: function (error) { console.log("Failed to download image!"); } }) }
这是我的后端/节点/快速代码:
app.post('/postFile', function (req, res, next) { var filename = req.body.filename; var file = req.body.file; var base64Data; fileBuffer = decodeBase64Image(file); blobSvc.createBlockBlobFromText('blob5', filename, fileBuffer.data, { 'contentType': fileBuffer.type }, function (error, result, response) { if (!error) { console.log("Uploaded" + result); } else { console.log(error); } }); }) // Decode file for upload function decodeBase64Image(dataString) { var matches = dataString.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/), response = {}; if (matches.length !== 3) { return new Error('Invalid input string'); } response.type = matches[1]; response.data = new Buffer(matches[2], 'base64'); return response; }
更新1: 根据加里(Gary)的建议,我尝试了以下操作,但由于我的供应商API没有文件URI,而是在GET上生成文件的端点(又使我迷失了如何传递端点),因此使代码有些混乱与加里(Gary)的例子很有意义)。例如,我的供应商端点“ http://vendorapi.net/ws/texture_0 ”返回一个名为“ Texture_0.png”的文件。
前端角度代码:
$scope.getFromVendor = function () { var filename = 'Texture_0.png';//jpg,txt... $http.post('/uploadapifiles', { filename: filename, url: 'http://vendorapi.net/ws/texture_0' }).success(function (data) { console.log(data); }, function (err) { console.log(err); }); }
服务器端下载处理(我认为这是最混乱的过程:
app.get(http://vendorapi.net/ws/texture_0', function (req, res, next) { res.download('http://vendorapi.net/ws/texture_0' + req.params.filename); })
服务器端上传处理:
app.post('/uploadapifiles', function (req, res, next) { var filename = req.body.filename; var r = request(req.body.url).pipe(fs.createWriteStream('http://vendorapi.net/ws/texture_0' + filename)) r.on('close', function () { blobsrv.createBlockBlobFromLocalFile('blob5', filename, 'http://vendorapi.net/ws/texture_0' + filename, function (error, result, response) { if (!error) { console.log("Uploaded" + result); } else { console.log(error); } }); }) });
按照您的原始想法,首先您需要在客户端获取文件内容数据,然后将数据发布到Express Web服务器。
如果您获取的文件很大,则会减慢您的站点速度,因为文件数据将通过HTTP传输两次,并且可能会发生其他问题。
此外,在我的测试项目中,几乎不直接处理文件内容数据。
因此,我尝试了另一种想法作为解决方法。
我只是将获取特定文件的API发布到服务器,将文件另存为文件保存在服务器目录中,然后将文件上传到服务器端的存储。这是我的代码段:
角形前端:
$scope.upload =function(){ var filename = (new Date()).getTime()+'.pdf';//jpg,txt... $http.post('http://localhost:1337/uploadfile', { filename: filename, url: 'http://localhost:1337/output/123.pdf'}).success(function (data) { console.log(data); },function(err){ console.log(err); }); }
后端:
我怀疑您获取文件形式的API会像后面一样。
router.get('/output/:filename', function (req, res, next) { res.download('upload/'+req.params.filename); })
后请求处理程序利用包请求,并且无需弄清文件类型或编码类型,createBlockBlobFromLocalFile便会将文件上传到您在Blob存储上提供的位置,API参考:
createBlockBlobFromLocalFile
router.post('/uploadfile', function (req, res, next) { var request = require('request'); var filename = req.body.filename; var tmpFolder = 'upload/', //this folder is to save files download from vendor URL, and should be created in the root directory previously. tmpFileSavedLocation = tmpFolder + filename; //this is the location of download files, e.g. 'upload/Texture_0.png' var r = request(req.body.url).pipe(fs.createWriteStream(tmpFileSavedLocation))//this syntax will download file from the URL and save in the location asyns r.on('close', function (){ blobsrv.createBlockBlobFromLocalFile('vsdeploy', filename, tmpFileSavedLocation, function (error, result, response) { if (!error) { console.log("Uploaded" + result); } else { console.log(error); } }); }) })