133

Expressjs 框架有一个sendfile()方法。在不使用整个框架的情况下如何做到这一点?

我正在使用 node-native-zip 创建一个存档,我想将它发送给用户。

4

5 回答 5

211

这是一个示例程序,它将通过从磁盘流式传输 myfile.mp3 来发送它(也就是说,它不会在发送文件之前将整个文件读入内存)。服务器侦听端口 2000。

[更新]正如@Aftershock 在评论中提到的那样,util.pump它已经消失并被 Stream 原型上的一个方法替换为pipe; 下面的代码反映了这一点。

var http = require('http'),
    fileSystem = require('fs'),
    path = require('path');

http.createServer(function(request, response) {
    var filePath = path.join(__dirname, 'myfile.mp3');
    var stat = fileSystem.statSync(filePath);

    response.writeHead(200, {
        'Content-Type': 'audio/mpeg',
        'Content-Length': stat.size
    });

    var readStream = fileSystem.createReadStream(filePath);
    // We replaced all the event handlers with a simple call to readStream.pipe()
    readStream.pipe(response);
})
.listen(2000);

取自http://elegantcode.com/2011/04/06/taking-baby-steps-with-node-js-pumping-data-between-streams/

于 2012-04-06T17:35:50.427 回答
18

您需要使用 Stream 在响应中发送文件(存档),更重要的是,您必须在响应标头中使用适当的 Content-type。

有一个示例函数可以做到这一点:

const fs = require('fs');

// Where fileName is name of the file and response is Node.js Reponse. 
responseFile = (fileName, response) => {
    const filePath = "/path/to/archive.rar"; // or any file format

    // Check if file specified by the filePath exists
    fs.exists(filePath, function (exists) {
        if (exists) {
            // Content-type is very interesting part that guarantee that
            // Web browser will handle response in an appropriate manner.
            response.writeHead(200, {
                "Content-Type": "application/octet-stream",
                "Content-Disposition": "attachment; filename=" + fileName
            });
            fs.createReadStream(filePath).pipe(response);
            return;
        }
        response.writeHead(400, { "Content-Type": "text/plain" });
        response.end("ERROR File does not exist");
    });
}

Content-Type 字段的目的是充分描述正文中包含的数据,以便接收用户代理可以选择适当的代理或机制将数据呈现给用户,或者以适当的方式处理数据。

“application/octet-stream”在 RFC 2046 中被定义为“任意二进制数据”,这种内容类型的目的是保存到磁盘 - 这是您真正需要的。

"filename=[name of file]" 指定要下载的文件名。

有关更多信息,请参阅此 stackoverflow 主题

于 2016-08-10T08:26:05.033 回答
4

这对我有帮助。/your-route到达路线后,它将立即开始下载文件。

app.get("/your-route", (req, res) => {

         let filePath = path.join(__dirname, "youe-file.whatever");

         res.download(filePath);
}

download的也是一种表达方式。

于 2021-06-01T07:53:30.883 回答
2

有点晚了,但快递有一个帮手,让生活更轻松。

app.get('/download', function(req, res){
  const file = `${__dirname}/path/to/folder/myfile.mp3`;
  res.download(file); // Set disposition and send it.
});
于 2021-05-07T21:41:25.707 回答
0

如果您需要仅使用 Node.js 本机发送 gzipped 文件:

const fs = require('fs') // Node.js module
const zlib = require('zlib') // Node.js module as well

let sendGzip = (filePath, response) => {
    let headers = {
        'Connection': 'close', // intention
        'Content-Encoding': 'gzip',
        // add some headers like Content-Type, Cache-Control, Last-Modified, ETag, X-Powered-By
    }

    let file = fs.readFileSync(filePath) // sync is for readability
    let gzip = zlib.gzipSync(file) // is instance of Uint8Array
    headers['Content-Length'] = gzip.length // not the file's size!!!

    response.writeHead(200, headers)
    
    let chunkLimit = 16 * 1024 // some clients choke on huge responses
    let chunkCount = Math.ceil(gzip.length / chunkLimit)
    for (let i = 0; i < chunkCount; i++) {
        if (chunkCount > 1) {
            let chunk = gzip.slice(i * chunkLimit, (i + 1) * chunkLimit)
            response.write(chunk)
        } else {
            response.write(gzip)
        }
    }
    response.end()
}
于 2021-11-26T13:18:09.627 回答