框架通过在 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 某一个字段