简体   繁体   English

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

[英]Node.js and Request - limiting the file size of downloaded file

I want to download a file with the Request library.我想下载一个带有请求库的文件。 It's pretty straightforward:这很简单:

request({
    url: url-to-file
}).pipe(fs.createWriteStream(file));

Since the URL is supplied by users (in my case) I would like to limit the maximum file size my application will download - let's say 10MB.由于 URL 是由用户提供的(在我的情况下),我想限制我的应用程序将下载的最大文件大小 - 假设为 10MB。 I could rely on content-length headers like so:我可以像这样依赖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));

The question is - how reliable is this?问题是 - 这有多可靠? I guess this callback will be called after the file has been downloaded, right?我想这个回调会在文件下载调用,对吗? But than it's too late if someone supplies the URL of file which is 1 GB.但是,如果有人提供 1 GB 的文件 URL,那就太晚了。 My application will first download this 1 GB of a file just to check (in the callback) that this is too big.我的应用程序将首先下载这 1 GB 的文件,只是为了检查(在回调中)这是否太大。

I was also thinking about good old Node's http.get() method.我也在考虑旧 Node 的http.get()方法。 In this case I would do this:在这种情况下,我会这样做:

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

What approach would you recommend to limit download max file size without actually downloading the whole thing and checking it's size after all?您建议使用什么方法来限制下载最大文件大小,而无需实际下载整个文件并检查其大小?

I would actually use both methods you've discussed: check the content-legnth header, and watch the data stream to make sure it doesn't exceed your limit.我实际上会使用您讨论过的两种方法:检查content-legnth标头,并观察数据流以确保它不超过您的限制。

To do this I'd first make a HEAD request to the URL to see if the content-length header is available.为此,我首先向 URL 发出HEAD请求,以查看content-length标头是否可用。 If it's larger than your limit, you can stop right there.如果它大于你的极限,你可以在那里停下来。 If it doesn't exist or it's smaller than your limit, make the actual GET request.如果它不存在或小于您的限制,则发出实际的GET请求。 Since a HEAD request will only return the headers and no actual content, this will help weed out large files with valid content-length s quickly.由于HEAD请求将只返回标头而没有实际内容,这将有助于快速清除具有有效content-length的大文件。

Next, make the actual GET request and watch your incoming data size to make sure that it doesn't exceed your limit (this can be done with the request module; see below).接下来,发出实际的GET请求并观察传入的数据大小以确保它不超过您的限制(这可以通过请求模块完成;见下文)。 You'll want to do this regardless of if the HEAD request found a content-length header, as a sanity check (the server could be lying about the content-length ).无论HEAD请求是否找到content-length标头,您都希望这样做,作为健全性检查(服务器可能对content-length撒谎)。

Something like this:像这样的东西:

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

The trick to watching the incoming data size using the request module is to bind to the data event on the response (like you were thinking about doing using the http module) before you start piping it to your file stream.使用 request 模块观察传入数据大小的技巧是在开始将data到文件流之前绑定到响应上的data事件(就像您正在考虑使用http模块一样)。 If the data size exceeds your maximum file size, call the response's abort() method.如果数据大小超过您的最大文件大小,请调用响应的abort()方法。

I had a similar issue.我有一个类似的问题。 I use now fetch to limit download size.我现在使用fetch来限制下载大小。

const response = await fetch(url, {
    method: 'GET',t
    size: 5000000, // maximum response body size in bytes, 5000000 = 5MB 
}).catch(e => { throw e })

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM