Express
本章节内容,主要介绍在 Midway 中如何使用 Express 作为上层框架,并使用自身的能力。
描述 | |
---|---|
包含独立主框架 | ✅ |
包含独立日志 | ✅ |
安装依赖
$ npm i @midwayjs/express@3 --save
$ npm i @types/body-parser @types/express @types/express-session --save-dev
或者在 package.json
中增加如下依赖后,重新安装。
{
"dependencies": {
"@midwayjs/express": "^3.0.0",
// ...
},
"devDependencies": {
"@types/body-parser": "^1.19.2",
"@types/express": "^4.17.13",
"@types/express-session": "^1.17.4",
// ...
}
}
也可以直接使用脚手架创建示例。
# npm v6
$ npm init midway --type=express-v3 my_project
# npm v7
$ npm init midway -- --type=express-v3 my_project
针对 Express,Midway 提供了 @midwayjs/express
包进行了适配,在其中提供了 Midway 特有的依赖注入、切面等能力。
信息
我们使用的 Express 版本为 v4
。
目录结构
.
├── src
│ ├── controller # controller接口的地方
│ ├── service # service逻辑处理的地方
| └── configuration.ts # 入口及生命周期配置、组件管理
├── test
├── package.json
└── tsconfig.json
开启组件
import { Configuration, App } from '@midwayjs/core';
import * as express from '@midwayjs/express';
import { join } from 'path';
@Configuration({
imports: [express],
importConfigs: [join(__dirname, './config')],
})
export class MainConfiguration {
@App()
app: express.Application;
async onReady() {}
}
控制器(Controller)
整个请求控制器的写法和 Midway 适配其他框架的类似。为了和其他场景的框架写法一致,在请求的时候,Midway 将 Express 的 req
映射为 ctx
对象。
import { Inject, Controller, Get, Provide, Query } from '@midwayjs/core';
import { Context, NextFunction } from '@midwayjs/express';
@Controller('/')
export class HomeController {
@Inject()
ctx: Context;
@Get('/')
async home(@Query() id) {
console.log(id); // req.query.id === id
return 'hello world'; // 简单返回,等价于 res.send('hello world');
}
}
你也可以额外注入 req
和 res
。
import { Inject, Controller, Get, Provide, Query } from '@midwayjs/core';
import { Context, Response, NextFunction } from '@midwayjs/express';
@Controller('/')
export class HomeController {
@Inject()
ctx: Context; // 即为 req
@Inject()
req: Context;
@Inject()
res: Response;
@Get('/')
async home(@Query() id) {
// this.req.query.id === id
}
}
Web 中间件
Express 的中间件写法比较特殊,它的参数不同。
import { Middleware } from '@midwayjs/core';
import { Context, Response, NextFunction } from '@midwayjs/express';
@Middleware()
export class ReportMiddleware implements IMiddleware<Context, Response, NextFunction> {
resolve() {
return async (
req: Context,
res: Response,
next: NextFunction
) => {
console.log('Request...');
next();
};
}
}
注意,这里我们导出了一个 ReportMiddleware
类,为了方便对接异步流程,resolve
返回可以是 async 函数。
Express 中的 next 方法,用于调用到下一个中间件,指的注意的是,Express 中间件并非洋葱模型,是单向调用。
路由中间件
我们可以把上面编写的中间件应用到单个 Controller 上,也可以将中间件应用到单个路由上。
import { Controller, Get, Provide } from '@midwayjs/core';
@Controller('/', { middleware: [ ReportMiddleware ]}) // controller 级别的中间件
export class HomeController {
@Get('/', { middleware: [ ReportMiddleware ]}) // 路由级别的中间件
async home() {
return 'hello world'
}
}
全局中间件
直接使用 Midway 提供的 app.generateMiddleware
方法,在入口处加载全局中间件。
// src/configuration.ts
import { Configuration, ILifeCycle } from '@midwayjs/core';
import * as express from '@midwayjs/express';
import { ReportMiddleware } from './middleware/report.middleware.ts'
@Configuration({
imports: [express],
})
export class MainConfiguration implements ILifeCycle {
@App()
app: express.Application;
async onReady() {
this.app.useMiddleware(ReportMiddleware);
}
}
除了加载 Class 形式的中间件外,也支持加载传统的 Express 中间件。
// src/configuration.ts
import { Configuration, ILifeCycle, App } from '@midwayjs/core';
import * as express from '@midwayjs/express';
import { join } from 'path';
@Configuration({
imports: [express],
})
export class MainConfiguration implements ILifeCycle {
@App()
app: express.Application;
async onReady() {
this.app.useMiddleware((req, res, next) => {
// xxx
});
}
}
你可以通过注入 app
对象,来调用到所有 Express 上的方法。