小编典典

通过Web服务下载文件,然后通过Node / Express将其推送到Azure Blob存储

angularjs

我需要从供应商的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);
            }
        });
    })
});

阅读 225

收藏
2020-07-04

共1个答案

小编典典

按照您的原始想法,首先您需要在客户端获取文件内容数据,然后将数据发布到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参考

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);
            }
        });
    })

})
2020-07-04