Node.js和Request - 限制下载文件的文件大小

Pon*_*ono 14 javascript node.js

我想用Request库下载一个文件.这非常简单:

request({
    url: url-to-file
}).pipe(fs.createWriteStream(file));
Run Code Online (Sandbox Code Playgroud)

由于URL是由用户提供的(在我的例子中),我想限制我的应用程序将下载的最大文件大小 - 比方说10MB.我可以依赖这样的content-length标题:

request({
    url: url-to-file
}, function (err, res, body) {
    var size = parseInt(res.headers['content-length'], 10);

    if (size > 10485760) {
        // ooops - file size too large
    }
}).pipe(fs.createWriteStream(file));
Run Code Online (Sandbox Code Playgroud)

问题是 - 这有多可靠?我想这个回调将在文件下载后调用,对吧?但是,如果有人提供1 GB的文件URL,那就太晚了.我的应用程序将首先下载这个1 GB的文件,只是为了检查(在回调中)这个太大了.

我也在考虑好的旧Node http.get()方法.在这种情况下,我会这样做:

var opts = {
    host: host,
    port: port,
    path: path
};

var file = fs.createWriteStream(fileName),
    fileLength = 0;

http.get(opts, function (res) {
    res.on('data', function (chunk) {
        fileLength += chunk.length;

        if (fileLength > 10485760) { // ooops - file size too large
            file.end();
            return res.end();
        }

        file.write(chunk);
    }).on('end', function () {
        file.end();
    });
});
Run Code Online (Sandbox Code Playgroud)

你会建议什么方法来限制下载最大文件大小而不是实际下载整个文件并检查它的大小?

Mik*_*e S 13

我实际上会使用您讨论过的两种方法:检查content-legnth标题,并观察数据流以确保它不超过您的限制.

为此,我首先HEAD向URL发出请求以查看content-length标头是否可用.如果它超过你的限制,你可以在那里停下来.如果它不存在或者小于您的限制,请提出实际GET请求.由于HEAD请求只返回标题而没有实际内容,因此这将有助于快速清除带有效content-lengths的大文件.

接下来,发出实际GET请求并观察您的传入数据大小,以确保它不超过您的限制(这可以通过请求模块完成;请参阅下文).无论HEAD请求是否找到content-length标题,您都希望这样做,作为完整性检查(服务器可能在说谎content-length).

像这样的东西:

var maxSize = 10485760;

request({
    url: url,
    method: "HEAD"
}, function(err, headRes) {
    var size = headRes.headers['content-length'];
    if (size > maxSize) {
        console.log('Resource size exceeds limit (' + size + ')');
    } else {
        var file = fs.createWriteStream(filename),
            size = 0;

        var res = request({ url: url });

        res.on('data', function(data) {
            size += data.length;

            if (size > maxSize) {
                console.log('Resource stream exceeded limit (' + size + ')');

                res.abort(); // Abort the response (close and cleanup the stream)
                fs.unlink(filename); // Delete the file we were downloading the data to
            }
        }).pipe(file);
    }
});
Run Code Online (Sandbox Code Playgroud)

使用请求模块观察传入数据大小的技巧是在开始将其传输到文件流之前绑定到data响应上的事件(就像您正在考虑使用http模块一样).如果数据大小超过最大文件大小,请调用响应的abort()方法.