在平常開發過程當中,有不少需求涉及到圖片/文件上傳,那麼用Koa如何實現?
以前的課程講過,Koa框架是一個基於中間件的框架,咱們所須要的一些功能都須要安裝相對應的中間件庫。
而要實現文件上傳,有不少插件:vue
這裏推薦使用koa-body!咱們來仔細研究一下它!web
以前使用 koa2 的時候,處理 post 請求使用的是 koa-bodyparser,同時若是是圖片上傳使用的是 koa-multer。
這二者的組合沒什麼問題,不過 koa-multer 和 koa-route(注意不是 koa-router) 存在不兼容的問題。ajax
koa-body結合了兩者,因此koa-body能夠對其進行代替。npm
在 koa2 中使用 koa-body,我使用的是全局引入,而不是路由級別的引入,由於考慮到不少地方都有 post 請求或者是文件上傳請求,不必只在路由級別引入。安全
npm i koa-body -D
const koaBody = require('koa-body'); const app = new koa(); app.use(koaBody({ multipart:true, // 支持文件上傳 encoding:'gzip', formidable:{ uploadDir:path.join(__dirname,'public/upload/'), // 設置文件上傳目錄 keepExtensions: true, // 保持文件的後綴 maxFieldsSize:2 * 1024 * 1024, // 文件上傳大小 onFileBegin:(name,file) => { // 文件上傳前的設置 // console.log(`name: ${name}`); // console.log(file); }, } }));
npm/koa-body服務器
router.post('/',async (ctx)=>{ console.log(ctx.request.files); console.log(ctx.request.body); ctx.body = JSON.stringify(ctx.request.files); });
爲何起這個標題呢,由於如今不少企業級的項目都不會選擇將一些圖片文件存儲在本身的服務器中,爲何?網絡
一般都會選擇阿里雲,騰訊雲,七牛雲等對象存儲OSS功能。併發
一般每一個平臺都會提供本身的SDK,並配套各類示例,方便省心。不適合咱們學習。app
舉個簡單的例子框架
var OSS = require('ali-oss') // 建立客戶端 var client = new OSS({ region: '', accessKeyId: '', accessKeySecret: '', bucket: '' }) const uploadSDK = async (obj) => { var fileName = obj.files.file.name var localFile = obj.files.file.path try { var result = await client.put(fileName, localFile) console.log(result.url) } catch (e) { console.log(e) } return result.url }
其餘功能如圖
var fs = require('fs') var path = require('path') const uploadStatic = async (obj) => { // 上傳單個文件 const file = obj.files.file // 建立可讀流 const reader = fs.createReadStream(file.path); let filePath = path.join(__dirname, '../static/upload/') + `/${file.name}`; // 建立可寫流 const upStream = fs.createWriteStream(filePath); // 可讀流經過管道寫入可寫流 reader.pipe(upStream); return "上傳成功!"; }
var fs = require('fs') var path = require('path') const uploadStatics = async (obj) => { // 上傳多個個文件 const files = obj.files.file for (let file of files) { // 建立可讀流 const reader = fs.createReadStream(file.path); let filePath = path.join(__dirname, '../static/upload/') + `/${file.name}`; // 建立可寫流 const upStream = fs.createWriteStream(filePath); // 可讀流經過管道寫入可寫流 reader.pipe(upStream); } return "上傳成功!"; }
涉及到大文件上傳,咱們就不能採用上面的方法,爲何?由於一般大文件上傳耗時很長,刷新/網速差等操做很容易致使文件上傳失敗,那麼如何去避免?
分片與併發結合,將一個大文件分割成多塊,併發上傳,極大地提升大文件的上傳速度。
當網絡問題致使傳輸錯誤時,只須要重傳出錯分片,而不是整個文件。另外分片傳輸可以更加實時的跟蹤上傳進度。
以vue項目爲例
webuploader: 一個簡單的以H5爲主,FLASH爲輔的現代文件上傳組件
<vue-upload ref="uploader" url="xxxxxx" uploadButton="#filePicker" multiple @fileChange="fileChange" @progress="onProgress" @success="onSuccess" ></vue-upload>
當咱們上傳大文件時,會被插件進行分片,ajax會有多個
原理:
咱們來看看upload發送的具體參數:
第一個配置(content-disposition)中的guid和第二個配置中的access_token,是咱們經過webuploader配置裏的formData,即傳遞給服務器的參數 後面幾個配置是文件內容,id、name、type、size等 其中chunks爲總分片數,chunk爲當前第幾個分片。圖片中分別爲12和9。當你看到chunk是11的upload請求時,表明這是最後一個upload請求了。