前端使用element-ui的el-upload組件上傳圖片
el-upload上傳圖片,當圖片上傳完成並獲得后端傳來的圖片地址(服務器地址)后,隱藏上傳組件並顯示圖片:
<el-upload
v-if="!imgUrl"
class="upload-demo"
drag
:action="uploadUrl"
:on-change="getFile"
accept=".jpg"
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">將文件拖到此處,或<em>點擊上傳</em></div>
<template v-slot:tip>
<div class="el-upload__tip">只能上傳jpg/png文件,且不超過500kb</div>
</template>
</el-upload>
<img v-else :src="imgUrl" alt="">
getFile (file) {
const { status, response } = file
if (status === 'success' && response?.code === 0) {
const { data } = response
this.imgUrl = data
}
}
后端
后端將獲取到的圖片放到node的靜態服務器上,服務器上這張圖片的地址也就是前端需要拿到並展示的圖片地址——后端項目的/app/public/下
具體流程
- 前端上傳圖片發送post請求;
- egg.js通過router調用controller.home.uploadImg ;
- 函數通過一系列操作將文件放到 后端項目/app/public 文件夾下;
- 傳遞給前端圖片地址 后端服務器地址/圖片名字(如若后端項目跑在7001端口 則回傳的url為 http://127.0.0.1:7001/xxx.jpg)。
前端頁面不能直接展示本地電腦里某個位置的圖片,會出現 Not allowed to load local resource 的錯誤:

async uploadImg(ctx) {
// 添加用戶信息
const part = ctx.multipart({ autoFields: true });
const stream = await part();
if (stream) {
const fileType = stream.mimeType.split('/')[ 1 ];
const filename = Date.now() + '.' + fileType || stream.filename.toLowerCase();
// UPLOAD_URL為'./app/public/'
const target = path.join(UPLOAD_URL, filename);
const writeStream = fs.createWriteStream(target);
await pump(stream, writeStream);
new Result(`http://${ctx.host}/public/${filename}`, '上傳成功').success(ctx.response);
}
}
為什么放到public目錄下就能直接訪問了呢?
我們來簡單看一下egg.js的運行機制
eggjs運行機制
eggjs 是功能更豐富、更規范的koa
使用koa時,你要寫一個項目,要往里面加很多中間件,要寫腳本加載routes文件夾下面的所有路由以及model文件夾下面的所有sequelize模型,koa僅僅是一個骨架,其他的都是你來完成,自由度高,但集成度低,每創建一個新項目都要做很多重復工作。egg.js是封裝了一套koa,可以理解成大禮包版koa,集成度高,可以輕松創建一個項目而不用做很多繁瑣的初期工作,解放生產力,更可貴的是有一套現成的規范提供給我們,不需要我們自己再去探索一套規范,比如router放哪里,controller放哪里,需不需要service,哪些放在service等等。

egg.js項目架構
綠色虛線框中的所有組件組成了一個Worker,這就是egg.js中實際執行代碼邏輯的進程,是一個node服務器。
- request進來后,先穿過中間件,自己定義的中間件都放在projectDir/app/middleware下,並在config中啟用;
- egg.js內置了egg-static中間件,將靜態資源放在projectDir/app/public中,只會經過egg-static中間件之前的中間件,最后egg-static直接響應給客戶端,不會到達其后的中間件以及Router;
- 如果不是public中的資源,將會穿越所有中間件,到達路由。一般所有的路由都放在router.js中,這個文件沒有任何邏輯,而是直接指向一個處理請求的controller,只起到目錄和索引的作用;
- Controller都放在projectDir/app/controller中,不含有具體的業務邏輯,業務邏輯都在Service中,Controller只負責調用並組合Service,最后將響應提交給客戶端;
- Service放在projectDir/app/service中,負責調用Model,進行具體業務;
- 除此之外,Worker中還有定時任務,寫在projectDir/app/schedule文件夾中;
- 各個部件的所有可操控行為,都可以在projectDir/config/中的配置文件中定義,配置文件可以同時有很多份,default會被具體環境的配置文件中的同名字段覆蓋,具體使用哪份配置,是根據EGG_SERVER_ENV這個環境變量的值。
