通过Webservice下载文件并通过Node / Express将其推送到Azure Blob存储

时间:2015-09-16 21:50:17

标签: angularjs node.js azure express

我需要从供应商的Web服务中检索文件并将它们推送到一个独特的blob容器中,以便用户拥有一个独特的工作空间&#34;。从本质上讲,我会从供应商那里获取文件,用户可以通过他们自己的blob容器中的文件来编辑这些文件,这样他们就不会互相交换工作文件。我有独特的blob容器工作,但需要&#34;下载&#34; /从我的供应商API获取文件并将它们推送到blob容器中。我能够成功检索文件,这将是单独的调用以获取PDF,文本文件和图像...但是如果我尝试将它们上传到Azure Blob存储,我在Node.js中收到以下错误:< / p>

  

TypeError:无法读取属性&#39;长度&#39;为null

我认为我需要在客户端将文件编码为base64以正确获取长度,并且已经看到了使用Canvas和toDataURL的一些示例,但我不确定这是否是实际下载的最佳方法直接推送到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的例子相比有意义)。例如,我的供应商端点&#39; http://vendorapi.net/ws/texture_0&#39;返回名为&#34; Texture_0.png&#34;。

的文件

前端角色代码:

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

1 个答案:

答案 0 :(得分: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);
})

post请求处理程序利用包request,并且没有必要确定文件类型或编码类型,createBlockBlobFromLocalFile将在blob存储上提供的位置上传文件,{{3 }}:

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

})