天天看點

eggjs 怎麼實作上傳圖檔(頭像)接口功能?

在實作上傳接口的時候,需要了解一下上傳的過程跟需要依賴的庫,以及測試上傳需要注意的問題。這裡順便說一下,注冊的時候去掉預設的圖檔頭像了,還有預設的簽名。

eggjs 怎麼實作上傳圖檔(頭像)接口功能?

圖檔上傳到伺服器的邏輯

  1. 首先前端調用上傳接口,将上傳的資源經過 FormData 執行個體封裝之後,傳給服務端
  2. 在服務端接收前端傳進來的圖檔資訊,通過​

    ​fs.readFileSync​

    ​ 方法,來讀取圖檔内容,并存放在變量中
  3. 找個存放圖檔的公共位置
  4. 通過​

    ​fs.writeFileSync​

    ​ 方法,将圖檔内容寫入公共位置
  5. 最後傳回圖檔位址

依賴的庫

需要對:​

​fs​

​、​

​moment​

​、​

​path​

​、​

​mkdirp​

​,有一定了解,fs,path 大家應該比較熟悉了,這裡就對 moment 以及 mkdirp 做一下簡單的介紹,具體的可以檢視文檔:

  • ​​mkdirp​​
  • ​​moment​​

mkdirp

mkdirp 是一款在 node.js 中像 ​

​mkdir -p​

​ 一樣遞歸建立目錄及其子目錄。

安裝

npm install      

使用

var mkdirp = require('mkdirp');
    
mkdirp('/tmp/foo/bar/baz', function (err) {
    if (err) console.error(err)
    else console.log('kaimo')
});
// 輸出 kaimo,/tmp/foo/bar/baz 目錄就會出現。      

moment

Moment.js 是一個輕量級的 JavaScript 時間庫,它友善了日常開發中對時間的操作,提高了開發效率。

安裝

npm install      

使用

var moment = require('moment');
moment().format();
// 格式化日期時間
moment(value).format('YYYY-MM-DD HH:mm:ss');

// moment(Date):可以使用預先存在的原生 Javascript Date 對象來建立 Moment。
var day = new Date(2011, 9, 16);
var dayWrapper = moment(day);
// 這會克隆 Date 對象,Date 的後續更改不會影響 Moment,反之亦然。      

eggjs 裡檔案上傳接收

egg 擷取上傳檔案的方法中官方給了兩種處理方法:這裡采用用 file 直接讀取

  1. file 直接讀取
  2. stream 流的方式:建立檔案寫入流,以管道方式寫入流

file 讀取方式

需要先在 ​

​config.defult.js​

​ 裡配置:

config.multipart = {
  mode:'file'
};      

控制層代碼:

// file 包含了檔案名,檔案類型,大小,路徑等資訊
// files[0]表示擷取第一個檔案,若前端上傳多個檔案則可以周遊這個數組對象
let file = ctx.request.files[0]
// 讀取檔案 
let filedata = fs.readFileSync(file.filepath);
// 将檔案存到指定位置
fs.writeFileSync(path.join('./', `uploadfile/test.png`), filedata)      

關于 stream 流的方式可以參考:​​【egg檔案上傳接收總結】​​

上傳接口實作

0、配置

需要先在 ​

​config.defult.js​

​​ 裡配置:檔案讀取配置,以及上傳頭像路徑,我們單獨把頭像放到本地的 ​

​kaimo-cost-images​

​ 檔案夾裡,跟項目分開,就不放到app的public檔案夾裡了,這個不需要手動去 D 盤建立檔案夾,到時會自動生成的。

// add your user config here
const userConfig = {
  // myAppName: 'egg',
  uploadAvatarDir: 'D://kaimo-cost-images/images/avatar', // 上傳頭像路徑
};
// 檔案讀取配置
config.multipart = {
  mode: 'file'
};      

1、建立路由

配置完,開始去 ​

​router.js​

​ 檔案裡寫一下請求上傳的路由

// 上傳頭像
router.post('/api/upload/avatar', verify_token, controller.upload.uploadAvatar);      

2、建立 upload.js 檔案

在 controller 檔案夾下建立 ​

​upload.js​

​ 用于處理上傳的相關邏輯

eggjs 怎麼實作上傳圖檔(頭像)接口功能?

3、編寫上傳邏輯

  1. 擷取檔案,​

    ​ctx.request.files[0]​

    ​表示擷取第一個檔案,若前端上傳多個檔案則可以周遊這個數組對象
  2. 擷取目前日期
  3. 建立圖檔儲存的路徑
  4. 建立目錄
  5. 生成路徑傳回
  6. 寫入檔案夾
  7. 清除臨時檔案,​

    ​ctx.cleanupRequestFiles()​

    ​;
'use strict';
const fs = require('fs');
const path = require('path');
const moment = require('moment');
const mkdirp = require('mkdirp');

const Controller = require('egg').Controller;

class UploadController extends Controller {
  async uploadAvatar () {
    const { ctx, config } = this;
    try {
      // 0、擷取檔案
      let file = ctx.request.files[0];
      console.log('擷取檔案', file);
      // ctx.request.files[0] 表示擷取第一個檔案,若前端上傳多個檔案則可以周遊這個數組對象
      let fileData = fs.readFileSync(file.filepath);
      console.log('fileData', fileData);
      // 1、擷取目前日期
      let day = moment(new Date()).format('YYYYMMDD');
      console.log('1、擷取目前日期', day);
      // 2、建立圖檔儲存的路徑
      let dir = path.join(config.uploadAvatarDir, day);
      console.log('2、建立圖檔儲存的路徑', dir);
      // 3、建立目錄
      await mkdirp(dir);
      // 4、生成路徑傳回
      let date = Date.now(); // 毫秒數
      let tempDir = path.join(dir, date + path.extname(file.filename)); // 傳回圖檔儲存的路徑
      console.log('毫秒數 extname', date, path.extname(file.filename));
      console.log('傳回圖檔儲存的路徑', tempDir);
      // 5、寫入檔案夾
      fs.writeFileSync(tempDir, fileData);
      ctx.body = {
        status: 200,
        desc: '上傳成功',
        data: tempDir,
      }
    } catch(error) {
      ctx.body = {
        status: 500,
        desc: '上傳失敗',
        data: null
      }
    } finally {
      // 6、清除臨時檔案
      ctx.cleanupRequestFiles();
    }
  }
}

module.exports = UploadController;      

測試接口

還是老樣子,先登入,然後拿到 token,在上傳一張圖檔,比如我選擇一隻修勾勾,然後點選發送。

eggjs 怎麼實作上傳圖檔(頭像)接口功能?

我們可以看到成功傳回了圖檔所在的路徑。當然實際項目裡不會傳回伺服器的路徑的,下一節我們在優化處理。

eggjs 怎麼實作上傳圖檔(頭像)接口功能?

繼續閱讀