灵活应用中间件机制,可以有效扩展架构的功能。中间件主要的作用有:拦截
、重整
- 拦截:比如通过中间件判断用户权限,如果没有权限则中止后续执行
- 重整:比如通过中间件对前端发来的数据进行验证,并转化为期望的类型
在这里,我们通过一个虚拟的需求,用中间件实现拦截
和重整
的逻辑:
- 需求:前端发送两个参数:a、b,后端计算二者之和,并返回前端
- 拦截:中间件判断参数是否为空,如果为空则中止后续执行
- 重整:将参数类型强制转换为Integer类型
创建中间件
1. 声明中间件
src/suite-vendor/test-party/modules/test-party/backend/src/config/config.js
- 1// middlewares
- 2config.middlewares = {
- 3 testInterception: {
- 4 bean: 'testInterception',
- 5 global: false,
- 6 dependencies: 'instance',
- 7 },
- 8 testRestructuring: {
- 9 bean: 'testRestructuring',
- 10 global: false,
- 11 dependencies: 'instance',
- 12 },
- 13};
名称 | 说明 |
---|---|
bean | 用于实现中间件逻辑的Bean组件名称 |
global | 是否为全局中间件 ,全局中间件会自动加载,局部中间件 需要手动指定 |
dependencies | 标明此中间件依赖哪些中间件,从而在那些中间件后面加载。一般要依赖于instance ,因为instance 提供了多实例 的基础逻辑 |
2. 定义中间件Bean组件
src/suite-vendor/test-party/modules/test-party/backend/src/bean/middleware.interception.js
- 1module.exports = ctx => {
- 2 class Middleware {
- 3 async execute(options, next) {
- 4 const { a, b } = ctx.request.body;
- 5 if (a === undefined || b === undefined) return ctx.throw(1002); // 1002: 'Incomplete Parameters'
- 6 // next
- 7 await next();
- 8 }
- 9 }
- 10 return Middleware;
- 11};
src/suite-vendor/test-party/modules/test-party/backend/src/bean/middleware.restructuring.js
- 1module.exports = ctx => {
- 2 class Middleware {
- 3 async execute(options, next) {
- 4 const { a, b } = ctx.request.body;
- 5 ctx.request.body.a = parseInt(a);
- 6 ctx.request.body.b = parseInt(b);
- 7 // next
- 8 await next();
- 9 }
- 10 }
- 11 return Middleware;
- 12};
3. 注册中间件Bean组件
src/suite-vendor/test-party/modules/test-party/backend/src/beans.js
- 1const middlewareTestInterception = require('./bean/middleware.interception.js');
- 2const middlewareTestRestructuring = require('./bean/middleware.restructuring.js');
- 3
- 4module.exports = app => {
- 5 const beans = {
- 6 // middleware
- 7 'middleware.testInterception': {
- 8 mode: 'ctx',
- 9 bean: middlewareTestInterception,
- 10 },
- 11 'middleware.testRestructuring': {
- 12 mode: 'ctx',
- 13 bean: middlewareTestRestructuring,
- 14 },
- 15 };
- 16 return beans;
- 17};
使用中间件
1. 配置API路由
因为testInterception
和testRestructuring
是局部中间件,因此需要手动在API路由上指定
src/suite-vendor/test-party/modules/test-party/backend/src/routes.js
- 1// test/feat/middleware
- 2{ method: 'post', path: 'test/feat/middleware/interception', controller: 'testFeatMiddleware', middlewares: 'test,testInterception' },
- 3{ method: 'post', path: 'test/feat/middleware/restructuring', controller: 'testFeatMiddleware', middlewares: 'test,testInterception,testRestructuring' },
2. 后端控制器逻辑
src/suite-vendor/test-party/modules/test-party/backend/src/controller/test/feat/middleware.js
- 1module.exports = app => {
- 2
- 3 class TestController extends app.Controller {
- 4
- 5 async interception() {
- 6 const { a, b } = this.ctx.request.body;
- 7 const c = parseInt(a) + parseInt(b);
- 8 this.ctx.success(c);
- 9 }
- 10
- 11 async restructuring() {
- 12 const { a, b } = this.ctx.request.body;
- 13 const c = a + b;
- 14 this.ctx.success(c);
- 15 }
- 16
- 17 }
- 18
- 19 return TestController;
- 20};
src/suite-vendor/test-party/modules/test-party/backend/src/controllers.js
- 1const testFeatMiddleware = require('./controller/test/feat/middleware.js');
- 2
- 3module.exports = app => {
- 4 const controllers = {
- 5 testFeatMiddleware,
- 6 };
- 7 return controllers;
- 8};
单元测试
在这里,我们采用单元测试
来验证中间件机制是否按预期运作
src/suite-vendor/test-party/modules/test-party/backend/test/controller/test/feat/middleware.test.js
- 1const { app, mockUrl, mockInfo, assert } = require('egg-born-mock')(__dirname);
- 2
- 3describe('test/controller/test/feat/middleware.test.js', () => {
- 4
- 5 it('action:interception', async () => {
- 6 // success
- 7 let result = await app.httpRequest()
- 8 .post(mockUrl('test/feat/middleware/interception'))
- 9 .send({
- 10 a: '1',
- 11 b: '2',
- 12 });
- 13 assert.equal(result.body.data, 3);
- 14
- 15 // fail
- 16 result = await app.httpRequest()
- 17 .post(mockUrl('test/feat/middleware/interception'))
- 18 .send();
- 19 assert.equal(result.status, 500);
- 20 });
- 21
- 22 it('action:restructuring', async () => {
- 23 // success
- 24 const result = await app.httpRequest()
- 25 .post(mockUrl('test/feat/middleware/restructuring'))
- 26 .send({
- 27 a: '1',
- 28 b: '2',
- 29 });
- 30 assert.equal(result.body.data, 3);
- 31 });
- 32
- 33});
评论: