egg:如何在控制器中拿到前端傳的參數

框架通過在 Controller 上綁定的 Context 實例,提供了許多便捷方法和屬性獲取用戶通過 HTTP 請求發送過來的參數。

query(get)

獲取 url 的 ?後面的數據,通過 ctx.query 拿到數據:

// GET /posts?category=egg&language=node
class PostController extends Controller {
  async listPosts() {
    const query = this.ctx.query;
    // {
    //   category: 'egg',
    //   language: 'node',
    // }
  }
}

Router params(get)

獲取 Router 上也可以申明參數,通過 ctx.params 拿到數據:

// app.get('/projects/:projectId/app/:appId', 'app.listApp');
// GET /projects/1/app/2
class AppController extends Controller {
  async listApp() {
  	// assert.equal 相當於 ==
    assert.equal(this.ctx.params.projectId, '1');
    assert.equal(this.ctx.params.appId, '2');
    // 或用解構賦值
    const { projectId, appId } = this.ctx.params
  }
}

body(post)

也就是 post、put、delete 等方法,框架內置了 bodyParser 中間件來對這兩類格式的請求 body 解析成 object 掛載到 ctx.request.body 上。

// POST /api/posts HTTP/1.1
// Host: localhost:3000
// Content-Type: application/json; charset=UTF-8
//
// {"title": "controller", "content": "what is controller"}
class PostController extends Controller {
  async listPosts() {
    assert.equal(this.ctx.request.body.title, 'controller');
    assert.equal(this.ctx.request.body.content, 'what is controller');
  }
}

可以在 config/config.default.js 配置解析請求的大小,會覆蓋框架默認值 100kb:

module.exports = {
  bodyParser: {
    jsonLimit: '1mb',
    formLimit: '1mb',
  },
};

注意區分:ctx.request.body 和 ctx.body :
ctx.body 是 ctx.response.body 的簡寫。

egg的file模式

1、在 config 文件中啓用 file 模式:

// config/config.default.js
exports.multipart = {
  mode: 'file',
};

2、上傳 / 接收文件:
前端:

<form method="POST" action="/upload?_csrf={{ ctx.csrf | safe }}" enctype="multipart/form-data">
  title: <input name="title" />
  file: <input name="file" type="file" />
  <button type="submit">Upload</button>
</form>

後端:

// app/controller/upload.js
const Controller = require('egg').Controller;
const fs = require('mz/fs');

module.exports = class extends Controller {
  async upload() {
    const { ctx } = this;
    const file = ctx.request.files[0];
    const name = 'egg-multipart-test/' + path.basename(file.filename);
    let result;
    try {
      // 處理文件,比如上傳到雲端
      result = await ctx.oss.put(name, file.filepath);
    } finally {
      // 需要刪除臨時文件
      await fs.unlink(file.filepath);
    }

    ctx.body = {
      url: result.url,
      // 獲取所有的字段值
      requestBody: ctx.request.body,
    };
  }
};

上傳多個文件可以看 egg 官網 傳送門

stream模式獲取file

const path = require('path');
const sendToWormhole = require('stream-wormhole');
const Controller = require('egg').Controller;

class UploaderController extends Controller {
  async upload() {
    const ctx = this.ctx;
    const stream = await ctx.getFileStream();
    const name = 'egg-multipart-test/' + path.basename(stream.filename);
    // 文件處理,上傳到雲存儲等等
    let result;
    try {
      result = await ctx.oss.put(name, stream);
    } catch (err) {
      // 必須將上傳的文件流消費掉,要不然瀏覽器響應會卡死
      await sendToWormhole(stream);
      throw err;
    }

    ctx.body = {
      url: result.url,
      // 所有表單字段都能通過 `stream.fields` 獲取到
      fields: stream.fields,
    };
  }
}

module.exports = UploaderController;

通過 ctx.getFileStream 獲取文件的前提:

  1. 只支持上傳一個文件。
  2. 上傳文件必須在所有其他的 fields 後面,否則在拿到文件流時可能還獲取不到 fields。

stream 模式上傳多個文件使用 ctx.multipart()

獲取header值

  1. ctx.headersctx.headerctx.request.headersctx.request.header 等價
  2. ctx.get(name)ctx.request.get(name) 獲取 header 某一個字段
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章