通过web服务下载文件,并通过节点/ EX preSS它推到的Azure Blob存储 [英] Download file via Webservice and Push it to Azure Blob Storage via Node/Express

查看:253
本文介绍了通过web服务下载文件,并通过节点/ EX preSS它推到的Azure Blob存储的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要从供应商的Web服务检索文件,并推到这些独特的BLOB容器,使用户有一个独特的工作空间。从本质上讲,我会从供应商处获得的文件下来,用户可能会在自己的blob容器,通过文件编辑这些,使他们没有越过对方的工作文件。我有独特的blob容器的工作,而是需要下载/从我的供应商的API获取文件,并将它们推入一个blob容器。我能够成功地检索文件,这将是单独调用得到一个PDF,文本文件和图像...但如果​​我试图将它们上传到Azure的Blob存储,我得到的Node.js以下错误:


  

类型错误:无法读取空的财产长度


我在想,我需要带code中的文件,在客户端的base64妥善得到的长度,并且已经看到了使用与toDataURL画布的一些例子,但我不确定这是否是最好的方法基本上对下载和直接推到的Azure Blob存储,尤其是因为我有文件如PDF(不知道PDF可以采用base64 EN codeD)。

下面是我的AngularJS控制器调用服务(注意,实际的端点可以根据哪些文件,他们称之为改变,所以我使用的文件来控制的变量,用户可以在表单中输入的客户端GET):

  $ scope.getFiles =功能(){$阿贾克斯({
网址:'http://vendorwebservice.net/ws/file1',
键入:GET,
成功:函数(结果){
的console.log(结果);
变种文件名='Texture_0.png';$ http.post('/ postFile',{文件名:文件名,文件:结果})成功(功能(数据){。
的console.log(数据);
},功能(错误){
的console.log(ERR);
});警报(文件中检索!);
},
错误:功能(错误){
的console.log(无法下载图像!);
}
})
}

下面是我的后端/节点/ EX preSS code:

  app.post('/ postFile'功能(REQ,资源,下一个){
    变种文件名= req.body.filename;
    var文件= req.body.file;
    VAR base64Data;
    fileBuffer =去codeBase64Image(文件);
    blobSvc.createBlockBlobFromText('blob5,文件名,fileBuffer.data,{'的contentType':fileBuffer.type},功能(错误,因此,响应){
        如果(!错误){
            的console.log(上传的+结果);
        }
        其他{
            的console.log(错误);
        }
    });
})上传//德code文件
功能去codeBase64Image(dataString){
    VAR匹配= dataString.match(/ ^数据:([A-ZA-Z - + \\ /] +);的base64,(+)$ /)
        响应= {};    如果(matches.length!== 3){
        返回新错误(无效输入字符串')​​;
    }    response.type =比赛[1];
    response.data =新缓冲液(比赛[2],'的base64');    返回响应;
}

更新1:
每加里的建议,我曾尝试以下,但因为我的供应商API没有文件的URI而是一个GET(又名,我失去了对如何通过端点产生一个文件端点搞砸codeA位与加里的例子是有道理的)。例如,我的供应商端点的 http://vendorapi.net/ws/texture_0 '返回文件名为Texture_0.png。

前端角code:

  $ scope.getFromVendor =功能(){
            变种文件名='Texture_0.png'; // JPG,TXT ...
            $ http.post('/ uploadapifiles',{文件名:文件名,网址:'http://vendorapi.net/ws/texture_0'})。成功(功能(数据){
                的console.log(数据);
            },功能(错误){
                的console.log(ERR);
            });
        }

服务器端下载处理(我相信这是一个最搞砸了:

  app.get(http://vendorapi.net/ws/texture_0',函数(REQ,资源,下一个){
    res.download('http://vendorapi.net/ws/texture_0'+ req.params.filename);
})

服务器端上传处理:

  app.post('/ uploadapifiles'功能(REQ,资源,下一个){    变种文件名= req.body.filename;
    变种R =请求(req.body.url).pipe(fs.createWriteStream('http://vendorapi.net/ws/texture_0'+文件名))
    r.on(关闭,函数(){
        blobsrv.createBlockBlobFromLocalFile('blob5,文件名http://vendorapi.net/ws/texture_0'+文件名,功能(错误,因此,响应){
            如果(!错误){
                的console.log(上传的+结果);
            }
            其他{
                的console.log(错误);
            }
        });
    })
});


解决方案

在你最初的想法,起初你客户端获取文件内容数据,然后发布数据到Ex preSS Web服务器。

如果你得到的文件是大尺寸,将您的网站放慢,因为文件的数据将通过HTTP传送了两次,它可能会出现其他的问题。

此外,在我的测试项目,它是很难直接与文件内容数据的处理。

所以,我想另一个想法作为一种解决方法。

我只是张贴得到特定的文件到服务器的API,拉将文件保存为服务器目录中的文件并上传的文件存储在服务器端。
这里是我的code片断:

角前端:

  $ scope.upload =功能(){
    变种文件名=(新的Date())的getTime()+'PDF'; // JPG,TXT ...
    $ http.post(的http://本地主机:1337 / uploadfile',{文件名:文件名,网址:的http://本地主机:1337 /输出/ 123.pdf'}).success(功能(数据){
        的console.log(数据);
    },功能(错误){
        的console.log(ERR);
    });
  }

后端:

我怀疑,你得到的文件形式会像背后的API。

  router.get('/输出/:文件名',函数(REQ,资源,下一个){
    res.download(上传/+ req.params.filename);
})

POST请求处理程序利用包申请,也没有必要弄清楚的文件类型或编码类型, createBlockBlobFromLocalFile 将上传你的Blob存储提供的位置的文件,的 API参考

  router.post('/ uploadfile',函数(REQ,资源,下一个){
    VAR请求=要求(请求);
    变种文件名= req.body.filename;
    VAR tmpFolder =上传/',//此文件夹来保存文件,从供应商的URL下载的,应该在根目录$ P $创建pviously。
        tmpFileSavedLocation = tmpFolder +文件名; //这是下载文件,例如位置上传/ Texture_0.png
    变种R =请求(req.body.url).pipe(fs.createWriteStream(tmpFileSavedLocation))//此语法将从URL下载文件,并保存在位置asyns
   r.on(关闭,函数(){
        blobsrv.createBlockBlobFromLocalFile('vsdeploy,文件名,tmpFileSavedLocation,功能(错误,因此,响应){
            如果(!错误){
                的console.log(上传的+结果);
           }
            其他{
                的console.log(错误);
            }
        });
    })})

I need to retrieve files from a vendor's Web service and push these into a unique blob container so users have a unique "workspace". Essentially, I would get files down from the vendor and users could edit these via the files in their own blob container so they don't cross each others working files. I have the unique blob containers working, but need to "download"/GET the files from my vendors API and push them into a blob container. I am able to successfully retrieve the files, which will be separate calls to get a PDF, text files, and images... but if I attempt to upload them to Azure Blob Storage, I get the following error in Node.js:

TypeError: Cannot read property 'length' of null

I am thinking that I need to encode the files as base64 on the client side to properly get the length, and have seen some examples of using a Canvas with toDataURL, but am unsure if this is the best method for essentially downloading and pushing directly to Azure Blob Storage, especially since I have files such as PDFs (not sure if PDFs can be base64 encoded).

Here is my AngularJS controller that calls the service (note that the actual endpoint may change depending on which files they call, so I am using a client side GET of files to control variables that a user may enter in a form):

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

Here is my backend/Node/Express code:

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

Update 1: Per Gary's suggestion I have tried the following, but messed up the code a bit since my vendors API does not have file URIs but rather endpoints that produce a file on a GET (aka, I am lost on how to pass the endpoint in versus Gary's example that makes sense). For example, my vendors endpoint of 'http://vendorapi.net/ws/texture_0' returns a file named "Texture_0.png".

Front end Angular Code:

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

Server Side Download Processing (I believe this is the one that is the most messed up:

app.get(http://vendorapi.net/ws/texture_0', function (req, res, next) {
    res.download('http://vendorapi.net/ws/texture_0' + req.params.filename);
})

Server Side Upload Processing:

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

解决方案

In your original idea, at first you get file content data in client side and then post the data to the Express web server.

If the file you get is in a large size, it will slow down your site because of the file data will be transferred twice via HTTP, and it may occur other problem.

Furthermore, in my test project, it is hardly to handle with file content data directly.

So I tried another idea as a workaround.

I just post the API of getting specific file to the server, pull the file save as a file on server directory and upload file to Storage on server side. Here is my code snippet:

Angular front end:

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

Back end:

I suspect the API which you get the file form would be like behind.

router.get('/output/:filename', function (req, res, next) {
    res.download('upload/'+req.params.filename);
})

The post request handler leverages package request, and there is no necessary to figure out file type or encoding type, createBlockBlobFromLocalFile will upload the file at the location you provide on blob storage, API reference:

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

})

这篇关于通过web服务下载文件,并通过节点/ EX preSS它推到的Azure Blob存储的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆