【问题标题】:Node.js Download File Using Content Disposition as FilenameNode.js 使用 Content Disposition 作为文件名下载文件
【发布时间】:2013-12-06 13:52:14
【问题描述】:

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

示例显示如下:

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

我可以使用请求回调获取文件名:

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

但这不会否定使用管道而不将下载的文件加载到内存中的好处吗?

【问题讨论】:

    标签: node.js request


    【解决方案1】:

    我从 yahoo 请求图像,它没有使用 content-disposition 标头,但我正在提取 datecontent-type 标头来构造文件名。这似乎与您尝试做的足够接近...

    var request = require('request'),
    fs = require('fs');
    
    var url2 = 'http://l4.yimg.com/nn/fp/rsz/112113/images/smush/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]));
    
    });
    

    请忽略我的图片选择:)

    【讨论】:

    • 哇,我忘了亚伦卡特。让我重新思考整个贾斯汀·贝伯的事情……营销!
    【解决方案2】:

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

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

    【讨论】:

    【解决方案3】:

    这是我的解决方案:

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

    此处发布的其他解决方案使用res.pipe,如果使用gzip 编码传输内容,则可能会失败,因为响应流包含原始(压缩)HTTP 数据。为避免此问题,您必须改用request.pipe。 (参见https://github.com/request/request#examples 的第二个示例。)

    使用request.pipe 时出现错误:“从响应中发出数据后,您无法进行管道传输。”,因为我在实际管道传输之前做了一些异步操作(创建一个目录来保存下载的文件)。我也遇到了一些问题,文件被写入没有内容,这可能是由于request 读取 HTTP 响应并对其进行缓冲。

    所以我最终使用through2 创建了一个中间缓冲流,这样我就可以在响应处理程序触发之前将请求通过管道传输给它,然后在知道文件名后从缓冲流传输到文件流。

    最后,无论文件名是使用 filename*=''file.txt 语法以纯格式还是 UTF-8 格式编码,我都会解析内容处置标头。

    我希望这可以帮助遇到与我相同问题的其他人。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-23
      • 1970-01-01
      • 2020-04-02
      • 2011-05-14
      • 1970-01-01
      • 1970-01-01
      • 2016-08-25
      相关资源
      最近更新 更多