2023-09-02
Angular
00
请注意,本文编写于 834 天前,最后修改于 643 天前,其中某些信息可能已经过时。

使用Koa2实现服务端的文件上传下载

js
const Koa = require("koa") const router = require("koa-router")(); const cors = require("koa2-cors") const fs = require('fs'); const path = require('path'); const {koaBody} = require('koa-body'); console.log(koaBody); const {saveFile,getFileStream,readFile} = require("./utils/file") const app = new Koa() /** 文件上传 */ router.post("/upload",function(ctx,next){ const file = ctx.request.files.file; const uniqueFilename = saveFile(file); ctx.body = { filename: uniqueFileName }; }) /** 文件下载 */ router.get("/download/:filename",async function(ctx,next){ const filename = ctx.params.filename; //request里面切出标识符字符串 let requestUrl = ctx.request.originalUrl; //获取资源文件的绝对路径 let filePath = path.resolve(__dirname + "/uploads/" + decodeURI(filename)); let resHred = readFile(ctx.headers.range, filePath); ctx.status = resHred.code ctx.set(resHred.head); ctx.set('Content-Disposition', `attachment; filename=${encodeURIComponent(filename)}`); ctx.set('Content-Type', 'application/octet-stream'); let stream = fs.createReadStream(filePath, resHred.code == 200 ? {} : { start: resHred.start, end: resHred.end }); stream.pipe(ctx.res); // //也可使用这种方式。 // stream.on('data', e => ctx.res.write(e)); // // 接收完毕 // stream.on('end', e => ctx.res.end()); ctx.respond = false; return }) router.post("/index",function(ctx,next){ ctx.body = { data:"token....", message:"获取token成功" } }) // app.use(async (ctx) => { // ctx.body = "token....." // }) // app.use( // cors({ // origin: function(ctx){ // return "*" //解决跨域 // }, // maxAge:5, // credentials:true,//是否携带cookie // allowMethods:["GET","POST","PUT","DELETE"] // }) // ) // koa-body 中间件来解析包含文件的 multipart/form-data 表单数据 app.use(koaBody({ multipart: true })); app.use(router.routes()) //app.use(router.allowedMethods()) app.listen(3000)

关于文件操作的工具函数file.js

js
const fs = require('fs'); const path = require('path'); function saveFile(file) { const reader = fs.createReadStream(file.path); const fileExtension = path.extname(file.name); const uniqueFileName = `${Date.now()}${fileExtension}`; const writer = fs.createWriteStream(path.join(__dirname, 'uploads', uniqueFileName)); reader.pipe(writer); return uniqueFileName; } function getFileStream(filename) { return fs.createReadStream(path.join(__dirname, '../uploads', filename)); } /** * [读文件] * @param {String} range [数据起始位] * @param {String} filePath [文件路径] * @param {Number} chunkSize [每次请求碎片大小 (900kb 左右)] */ function readFile(range, filePath, chunkSize = 499999 * 2) { //mime类型 const mime = { "css": "text/css", "gif": "image/gif", "html": "text/html", "ico": "image/x-icon", "jpeg": "image/jpeg", "jpg": "image/jpeg", "js": "text/javascript", "json": "application/json", "pdf": "application/pdf", "png": "image/png", "svg": "image/svg+xml", "swf": "application/x-shockwave-flash", "tiff": "image/tiff", "txt": "text/plain", "mp3": "audio/mp3", "wav": "audio/x-wav", "wma": "audio/x-ms-wma", "wmv": "video/x-ms-wmv", "xml": "text/xml", "mp4": "video/mp4" }; // 获取后缀名 let ext = path.extname(filePath); ext = ext ? ext.slice(1) : 'unknown'; //未知的类型一律用"text/plain"类型 let contentType = mime[ext.toLowerCase()]; //建立流对象,读文件 let stat = fs.statSync(filePath) let fileSize = stat.size; let head = { code: 200, head: { 'Content-Length': fileSize, 'content-type': contentType, } }; console.log("range: ",range); if (range) { // 大文件分片 let parts = range.replace(/bytes=/, "").split("-"); let start = parseInt(parts[0], 10); let end = parts[1] ? parseInt(parts[1], 10) : start + chunkSize; end = end > fileSize - 1 ? fileSize - 1 : end; chunkSize = (end - start) + 1; head = { code: 206, filePath, start, end, head: { 'Content-Range': `bytes ${start}-${end}/${fileSize}`, 'content-type': contentType, 'Content-Length': chunkSize, 'Accept-Ranges': 'bytes' } } } return head; } module.exports = { saveFile, getFileStream, readFile }
如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:千寻

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!