使用HTTP Range头发送的Node.js脚本请求导致返回的字节数超出请求的范围。

4

我正在尝试编写一个Node.js脚本,该脚本通过命令行接收指定的URL(用于下载文件)。使用HTTP范围请求头,脚本以可配置的块数和块大小下载文件,然后按正确的字节顺序写入输出文件。

目前希望使用2个1 MiB(1,048,576字节)的块来完成,总共2 MiB(2,097,152 B)。

我目前遇到的问题在执行中或只是我的理解有误,即我的脚本每个请求都会写入大约1,800,000字节,导致总共3,764,942字节。不确定这些额外字节来自哪里?

这是由于我错过了脚本中的错误还是请求库产生的开销,或者我对MiB转换成字节的理解有所偏差?

  • 当前文件内容并不重要,只需保证正确的字节数按正确的顺序排列即可。
  • 用设置为1MiB块的范围头卷曲测试URL,然后将其附加到文件中,结果接近预期的总字节数。curl 'https://eloquentjavascript.net/Eloquent_JavaScript.pdf' -i -H "Range: bytes=0-2097152" => 2097435 B文件
  • 我在终端中运行此命令node index.js --url='https://eloquentjavascript.net/Eloquent_JavaScript.pdf' --file='newfile.txt' --chunks 2
  • 使用Node v10.12.0,minimist v1.2.0和request-promise v4.2.2

整个脚本如下:

'use strict';

const argv = require('minimist')(process.argv.slice(2), {
    default: {
        file: 'output.txt',
        MiB: 1,
        chunks: 4
    }
});
const fs = require('fs');
const request = require('request-promise');

// Source URL must be specified through command line option.
if (!argv.url) throw Error('Source URL is required!');

const options = {
    method: 'GET',
    uri: argv.url
}

const determineChunkRange = (step) => {
    // 1 Mib = 1,048,576 B.
    // Only 1 MiB chunks are downloaded.
    const chunkSize = argv.MiB * 1048576;
    const startOfRange = step === 0 ? 0 + ((chunkSize * step)) : 1 + ((chunkSize * step));
    const endOfRange = startOfRange + chunkSize;

    return {'Range': `bytes=${startOfRange}-${endOfRange}`}
}

const getOptions = (step) => {
    options.headers = determineChunkRange(step);

    return options;
}

const addDataToFile = (data) => {
    try {
        fs.appendFileSync(argv.file, data);
        console.log("Data written to file.");
    } catch (err) {
        console.log(`Error appending to ${argv.file}`, err);
    }
}

// Create or Replace file with specific filename.
fs.writeFileSync(argv.file, '');
console.log("Successfully created new file.");

// Make specified number of requests.
for (let i = 0; i < argv.chunks; i++) {
    const options = getOptions(i);

    // make request to specified URL.
    request(options)
        .then(response => {
            console.log(i, options)
            addDataToFile(response)
        })
        .catch(error => {
            console.log(`Error making request to ${argv.url}`, error)
        });
}

1
你确定响应只包含文件吗?在将其写入文件之前记录响应。 - yeya
1个回答

1
问题在于你添加的是整个响应对象,而不是它的内容/主体。
你可以使用响应的data事件来获取内容,然后将其附加到文件中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接