场景:
服务端接收到下载请求,根据请求路径拼接文件地址,读取文件流返回给前端
报错:
error Error: write EPIPE
原代码:
本地环境可实现下载
router.get('/download',
koaBody(),
function (ctx, next) {
const {id,url} = ctx.query
if (!id || !url ) {
return ctx.body = { msg: '请求参数错误' }
}
try {
// let fileObj = downloadZip(id,url)
ctx.set("Access-Control-Expose-Headers","content-disposition");
ctx.set(
"Content-disposition",
"attachment;filename=" + encodeURIComponent(path.basename(url))
);
let filePath = path.resolve(__dirname, "../../"+url);
const stream = fs.createReadStream(filePath)
ctx.body = fileObj.stream; //返回文件流
} catch(err) {
ctx.code = 500;
ctx.body = {
code: 'error',
msg: '服务器内部错误'
};
}
}
)
修改后:
ctx.set("Content-Type", "application/zip");
stream.on('error', (err) => {
console.error(`Error reading file: ${err}`);
ctx.status = 500; // 设置状态码为500(服务器内部错误)
ctx.body = { msg: '服务器内部错误' };
});
// 将文件流直接pipe到响应对象,这样Node.js会自动处理数据的传输
stream.pipe(ctx);
主要代码:stream.pipe(ctx);
调用pipe方法,这样Node.js会自动处理数据的传输,
注意:在Koa中,通常可以直接使用ctx来pipe流,因为Koa会自动处理它。但在原生node中需要使用ctx.res
完整代码
router.get('/download',
koaBody(),
function (ctx, next) {
const {id,url} = ctx.query
if (!id || !url ) {
return ctx.body = { msg: '请求参数错误' }
}
try {
// let fileObj = downloadZip(id,url)
ctx.set("Access-Control-Expose-Headers","content-disposition");
ctx.set(
"Content-disposition",
"attachment;filename=" + encodeURIComponent(path.basename(url))
);
ctx.set("Content-Type", "application/zip");
let filePath = path.resolve(__dirname, "../../"+url);
const stream = fs.createReadStream(filePath)
stream.on('error', (err) => {
console.error(`Error reading file: ${err}`);
ctx.status = 500; // 设置状态码为500(服务器内部错误)
ctx.body = { msg: '服务器内部错误' };
});
// 将文件流直接pipe到响应对象,这样Node.js会自动处理数据的传输
stream.pipe(ctx);
} catch(err) {
ctx.code = 500;
ctx.body = {
code: 'error',
msg: '服务器内部错误'
};
}
}
)