上傳圖片到服務器是一個很常見的需求, 應該實現(xiàn)起來很簡單. 但是之前沒這方面經驗, 折騰了一番.
調研
數(shù)據(jù)庫中應該只保存圖片的鏈接, 圖片保存在文件系統(tǒng)中, 可以是服務器本地, 可以是自己部署的獨立圖片服務器, 也可以是第三方服務器.
MongoDB中, BSON文件的上顯示16MB. 所以如果圖片不超過這個上限, 就可以存BSON; 否則要用GridFS.
對我來說, 最理想的當然是使用第三方圖片服務器了. 但是現(xiàn)在并不想花這個錢(囧rz). 所以想先試試存在自己的服務器本地.
界面怎么寫?
上傳文件有個專門的控件, input[type="file"]
. 瀏覽了幾個網(wǎng)站的實現(xiàn), 都是把input[type="file"]
隱藏起來(因為它太丑), 然后在相同的區(qū)域擺上一個按鈕之類的東西(好看一些), 用戶點了按鈕其實點擊了input[type="file"]
.
示例如下:
<label class="btn btn-primary file-chooser">
Change Picture
<input type="file" accept=".jpg, .jpeg, .png" @change="uploadAvatar">
</label>
input[type="file"]
支持屬性accept
, 上面的代碼只接受.jpg, .jpeg, .png
文件.
@change="uploadAvatar"
是vue中監(jiān)聽input[type="file"]
的change
事件. 用戶選擇的圖片會成為e.target.files[0]
.
uploadAvatar(e) {
service.uploadAvatar(e.target.files[0]);
}
請求怎么發(fā)?
我用的是axios處理請求. 搜了一下需要用multipart/form-data
的content-type
發(fā)送, 具體如下:
// service.js
uploadAvatar(avatar) {
let data = new FormData();
data.append('avatar', avatar);
return axios.post('/upload-avatar', data, {
headers: { 'content-type': 'multipart/form-data' }
});
}
后端怎么接?
我用的是express + mongodb. 其實我本來打算存BSON的, 反正頭像不用16MB那么大.
但是搜了一下可以用multer
, 陰差陽錯存到本地了.
npm install -S multer
后:
// index.js
const multer = require('multer');
const avatarUpload = multer({ dest: 'public/avatar/' });
app.use(express.static('public'));
第二行創(chuàng)建了文件夾public/avatar
作為存儲圖片的地點.
第三行是將整個public
文件夾都作為靜態(tài)資源, 讓外部可以訪問.
然后寫路由:
router.post(
'/upload-avatar',
authenticator,
avatarUpload.single('avatar'),
(req, res) => {
// Set { new: true } to return the updated one, rather than the original one.
User.findByIdAndUpdate(req.user.id, { avatar: req.file.path }, { new: true }).then(user => {
res.json({ message: "ok" });
});
}
);
authenticator
是我在JWT上手: Express+Passport做的用戶身份JWT驗證邏輯, 此處請忽略. 示例代碼里面沒刪除是因為req.user.id
需要它.
avatarUpload.single('avatar')
引入了multer
的中間件, 讀取請求中的key為avatar
的文件, 返回到req.file
中. req.file
是一個object
, 里面有mimetype
等信息, 我們需要的是req.file.path
, 即服務器本地的地址.
User.findByIdAndUpdate
就是把這條信息更新到mongoDB中.
至此, 打完收工.
回頭來看, 感覺真簡單. 但是調研的時候接觸到了很多聽都沒聽過的東西, BSON, GridFS, multer, 充滿不確定性 :P.