2

我正在使用node.js为Azure文件存储创建文件服务。我为此使用azure-storage-node (http://azure.github.io/azure-storage-node/)在响应中发送数据流 - node.js - 使用node.js的Azure文件服务

我试图从Azure文件存储下载文件。以下是我的代码片段

// Download a file from Share 
exports.get = function(request, response){ 
    var shareName = request.headers.sharename; 
    var dirPath = request.headers.directorypath; 
    var fileName = request.headers.filename; 

    var fileService = azure.createFileService(); 

    var readStream = fileService.createReadStream(shareName, dirPath, fileName); 

    var dataLength = 0; 
    var body = ''; 
    readStream.on('data', function (chunk) { 
    dataLength += chunk.length; 
    }) 

    readStream.on('end', function(){ 
     console.log('The length was:', dataLength); 
    }); 

    response.setHeader('Content-Type', 'application/json'); 
    response.send(statusCodes.OK, JSON.stringify("Success!")); 

} 

我能够获取数据流。但是,我怎样才能在响应中发送流,以便我们可以在其余的调用中得到它。

我试图readStream.pipe(response);

response.write(typeof chunk); 
response.end() but it doesnt work; 

我是新来Node.js的请帮助我。

更新:

我试过以下内容。

response.writeHead(200, {'Content-Type': 'application/json'}); 

var readStream = fileService.createReadStream(shareName, dirPath, fileName); 
readStream.pipe(response); 

但它抛出follwing错误。

ERROR 
An unhandled exception occurred. Error: Can't set headers after they are sent. 
    at ServerResponse.OutgoingMessage.setHeader (http.js:679:11) 
    at ServerResponse.res.setHeader (D:\home\site\wwwroot\node_modules\express\node_modules\connect\lib\patch.js:59:22) 
    at ServerResponse.res.set.res.header (D:\home\site\wwwroot\node_modules\express\lib\response.js:518:10) 
    at addDefaultHeaders (D:\home\site\wwwroot\runtime\request\requesthandler.js:582:9) 
    at ServerResponse.<anonymous> (D:\home\site\wwwroot\runtime\request\requesthandler.js:291:13) 
    at ServerResponse._.wrap [as end] (D:\home\site\wwwroot\node_modules\underscore\underscore.js:692:22) 
    at ChunkStream.onend (stream.js:66:10) 
    at ChunkStream.EventEmitter.emit (events.js:126:20) 
    at ChunkStream.end (D:\home\site\wwwroot\App_Data\config\scripts\node_modules\azure-storage\lib\common\streams\chunkstream.js:90:8) 
    at Request.onend (stream.js:66:10) 

fileService.createReadStream(shareName, dirPath, fileName);返回的数据类型是ChunkStream

更新时间:

这是我更新的代码工作。

var option = new Object(); 
    option.disableContentMD5Validation = true; 
    option.maximumExecutionTimeInMs = 20 * 60000; 
    option.timeoutIntervalInMs = 20 * 6000; 

    fileService.getFileToStream(shareName, dirPath, fileName, response, option, function(error, result, res) { 
     if(!error) { 
      if(res.isSuccessful) { 
       console.log(result); 
     console.log(res); 
     console.log("Success!"); 
     } 
     } 
    }); 

但更频繁我得到以下错误。

ERROR 
An unhandled exception occurred. Error: Can't set headers after they are sent. 
at ServerResponse.OutgoingMessage.setHeader (http.js:679:11) 
at ServerResponse.res.setHeader (D:\home\site\wwwroot\node_modules\express\node_modules\connect\lib\patch.js:59:22) 
at ServerResponse.res.set.res.header (D:\home\site\wwwroot\node_modules\express\lib\response.js:518:10) 
at addDefaultHeaders (D:\home\site\wwwroot\node_modules\azure-mobile-services\runtime\request\requesthandler.js:590:9) 
at ServerResponse. (D:\home\site\wwwroot\node_modules\azure-mobile-services\runtime\request\requesthandler.js:299:13) 
at ServerResponse._.wrap as end 
at Request.onend (stream.js:66:10) 
at Request.EventEmitter.emit (events.js:126:20) 
at IncomingMessage.Request.onRequestResponse.strings (D:\home\site\wwwroot\App_Data\config\scripts\node_modules\azure-storage\node_modules\request\request.js:1153:12) 
at IncomingMessage.EventEmitter.emit (events.js:126:20) 
+0

试着把readStream.pipe(response);在声明readStream并删除其他所有内容之后。我也相信你不能发送内容类型的应用程序/ JSON当你发送一个二进制文件(我不知道这一点)。 –

+0

我试过“.pipe(响应)”。但是它给出错误“发生了未处理的异常,错误:发送后无法设置标题。” fileService.createReadStream的输出是一个ChunckStream。我们如何管理块流来响应。 – Sniper

回答

3

的类的NodeJS实现http.ServerResponseWritable Stream接口,请参考API的NodeJS和https://nodejs.org/api/http.html#http_class_http_serverresponsehttps://nodejs.org/api/stream.html#stream_class_stream_writable_1

所以,你只需要在示例代码“getFileToStream” http://azure.github.io/azure-storage-node/#toc8使用对象response不是流作家fs.createStreamWriter(...)的,当你发送数据流转换为响应的NodeJS。

这是下面我的示例代码:

var http = require('http'); 
var azure = require('azure-storage'); 
var fileService = azure.createFileService('<storage_key_name>','<storage_access_key>'); 

http.createServer(function (request, response) { 
    var shareName = request.headers.sharename; 
    var dirPath = request.headers.directorypath; 
    var fileName = request.headers.filename; 
    response.setHeader('Content-Type', 'application/json'); 
    fileService.getFileToStream(shareName, dirPath, fileName, response, {disableContentMD5Validation: true}, function(error, result, response) { 
      if(!error) { 
        //console.log(result); 
        //console.log(response); 
        if(response.isSuccessful) { 
           console.log("Success!"); 
        } 
      } 
    }); 
}).listen(1337, "127.0.0.1"); 

console.log('Server running at http://127.0.0.1:1337/'); 

问候。


对于来自Azure的文件存储变得文件超过4MB时,有一个请求头x-ms-range-get-content-md5,它会导致状态代码400(错误请求)错误,请参阅Azure的文件存储的Get File REST API文档https://msdn.microsoft.com/en-us/library/azure/dn194274.aspx,见下图:

enter image description here

所以我回顾了Azure的文件存储SDK为节点源(https://github.com/Azure/azure-storage-node/blob/master/lib/services/file/fileservice.js)。对于功能getFileToTextgetFileToLocalFilecreateReadStreamgetFileToStream,您需要设置options.disableContentMD5Validation属性以避免该错误,请参阅下文。

  • @param {boolean} [options.disableContentMD5Validation] When set to true, MD5 validation will be disabled when downloading files.

,并且指的getFileToStream源为例如:

enter image description here

在我的示例代码,需要在调用函数getFileToStream的前添加代码{disableContentMD5Validation: true}作为选项。

+0

非常感谢#Peter Pan。它适用于4MB以下文件的文件。对于4MB以上,它会在java.net.SocketInputStream.read(Unknown Source)处发生错误Connection reset \t。使用node.js文件服务上传和下载的最大大小是多少? – Sniper

+0

@Sniper请参阅https://azure.microsoft.com/en-us/documentation/articles/azure-subscription-service-limits/#storage-limits。 –

+0

@Sniper对于4MB以上的加载错误,请查看已更新的帖子。 –

1

你可能想通过这种方式来尝试:

exports.get = function(request, response) { 
    var shareName = request.headers.sharename; 
    var dirPath = request.headers.directorypath; 
    var fileName = request.headers.filename; 

    var fileService = azure.createFileService(); 
    var readStream = fileService.createReadStream(shareName, dirPath, fileName);  

    var dataLength = 0; 
    readStream.on('data', function (chunk) { 
    dataLength += chunk.length; 
    }) 

    readStream.on('end', function(){ 
    response.setHeader('Content-Type', 'application/json'); 
    response.setHeader('Content-Length', dataLength); 
    }); 

    readStream.pipe(response); 

    response.on('finish', function (chunk) { 
    response.send(statusCodes.OK, JSON.stringify("Success!")); 
    }) 
} 
+0

我试过这买它抛出错误“发生未处理的异常。错误:发送后无法设置标头。”我正在用错误日志更新问题。 – Sniper

+0

你是否在'readStream.pipe(response)'后调用了任何'response.setHeader()'?或者在“响应”的事件处理程序中? –

+0

已更新答案,以避免在发送响应后设置标题。 –

相关问题