框架通過在 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
獲取文件的前提:
- 只支持上傳一個文件。
- 上傳文件必須在所有其他的 fields 後面,否則在拿到文件流時可能還獲取不到 fields。
stream 模式上傳多個文件使用 ctx.multipart()
獲取header值
ctx.headers
,ctx.header
,ctx.request.headers
,ctx.request.header
等價ctx.get(name)
,ctx.request.get(name)
獲取 header 某一個字段