如何使用Node.js核心模块实现用户从服务器下载文件?
使用Node.js核心模块实现文件下载服务
基础实现(http + fs模块)
借助Node.js的http和fs核心模块就能快速实现文件下载服务,核心思路是创建HTTP服务器,当用户请求指定文件时,读取文件并通过响应流返回给客户端,同时设置正确的响应头触发浏览器的下载行为。
示例代码:
const http = require('http'); const fs = require('fs'); const path = require('path'); const server = http.createServer((req, res) => { // 可根据请求路径动态调整要下载的文件路径 const filePath = path.join(__dirname, 'target-file.pdf'); // 检查文件是否存在 fs.access(filePath, fs.constants.F_OK, (err) => { if (err) { res.writeHead(404, { 'Content-Type': 'text/plain' }); res.end('文件不存在'); return; } // 获取文件信息,用于设置响应头的文件大小 fs.stat(filePath, (statErr, stats) => { if (statErr) { res.writeHead(500, { 'Content-Type': 'text/plain' }); res.end('读取文件信息失败'); return; } // 设置响应头触发下载行为 res.writeHead(200, { 'Content-Type': 'application/octet-stream', // 通用二进制类型,兼容多数文件格式 'Content-Disposition': `attachment; filename="downloaded-file.pdf"`, // 指定下载后的文件名 'Content-Length': stats.size }); // 创建文件读取流,流式传输避免大文件占满内存 const fileStream = fs.createReadStream(filePath); // 将文件流管道到响应对象 fileStream.pipe(res); // 处理流读取错误 fileStream.on('error', (streamErr) => { res.writeHead(500, { 'Content-Type': 'text/plain' }); res.end('读取文件出错'); }); }); }); }); const PORT = 3000; server.listen(PORT, () => { console.log(`服务器运行在 http://localhost:${PORT}`); });
关键细节说明
- 响应头配置:
Content-Disposition: attachment是触发浏览器下载的核心设置,filename定义用户下载后看到的文件名;若想让浏览器直接预览文件(如图片、文本),可将attachment替换为inline。Content-Type建议根据文件实际类型设置(如image/png、text/plain),不确定类型时用application/octet-stream通用类型。Content-Length告知浏览器文件总大小,方便显示下载进度。
- 流式传输优势:使用
fs.createReadStream而非fs.readFile,后者会将整个文件加载到内存,大文件场景下易导致内存溢出;流式传输分块发送数据,内存占用更稳定。 - 安全与错误处理:必须处理文件不存在、读取失败等异常,避免服务器崩溃;若支持动态文件路径,需校验请求路径防止目录遍历攻击(如用
path.normalize限制文件在指定目录内)。
动态文件下载(根据URL路径匹配)
若需支持用户通过不同URL下载不同文件,可解析请求URL动态确定文件路径:
// 在createServer回调中修改文件路径逻辑 const requestedFileName = req.url.slice(1); // 假设请求URL为 /report.xlsx,此处获取report.xlsx const allowedDir = path.join(__dirname, 'downloads'); const filePath = path.join(allowedDir, requestedFileName); // 校验路径是否在允许的目录内,防止目录遍历 if (!filePath.startsWith(allowedDir)) { res.writeHead(403, { 'Content-Type': 'text/plain' }); res.end('无权访问该文件'); return; } // 后续文件读取、响应逻辑同基础实现
内容的提问来源于stack exchange,提问作者Yeshwanth. 061
相关产品推荐
相关产品推荐

