将 Nest.js 应用导入为简单的 Express 中间件
Import a Nest.js app as a simple Express middleware
我有一个 Nestjs 应用程序(一个 Rest API),我想将其导入另一个节点模块,作为一个简单的 Express 中间件(不是 Nest 中间件)。其实我还是没法让它工作。
// main.ts
// => The main file of my Nest app, this one is working properly.
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
// app.middleware.ts
import {Injectable, NestMiddleware} from '@nestjs/common';
import {NestFactory} from '@nestjs/core';
import {AppModule} from './app.module';
import {ExpressAdapter} from '@nestjs/platform-express';
import express, {Request, Response} from 'express';
const bootstrap = async () => {
const expressApp = express();
const adapter = new ExpressAdapter(expressApp);
const app = await NestFactory.create(AppModule, adapter);
await app.init();
return app;
};
@Injectable()
export class AppMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: Function) {
return bootstrap();
}
}
// express-app.ts
// => Here I'm trying to load my app through a simple Express middleware, but it doesn't works.
import express from 'express';
import { AppMiddleware } from './app.middleware';
const app = express();
const PORT = process.env.PORT || 3000;
app.use((req, res, next) => {
const app = new AppMiddleware().use(req, res, next);
app.then(next);
});
app.listen(PORT, () => {
console.log(`app running on port ${PORT}`);
});
当 运行从 main.ts
连接我的应用程序时,它工作正常(所有路由都在工作,我得到了正确的数据)。但是,当我尝试通过 express-app.ts
运行 应用程序时,所有路由似乎都在工作(它们显示在终端中),但在任何情况下我都没有返回 JSON 对象我收到此错误:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>[object Object]</pre>
</body>
</html>
嵌套组件版本:
- @nestjs/common: "^6.10.14"
- @nestjs/core: "^6.10.14"
- @nestjs/platform-express: "^6.10.14"
- express: "^4.16.4"
虽然我不容忍将 Nest 本身用作中间件,但这是可能的。使用 nest new express-server -p npm
的基本设置来创建新的 NestJS 应用程序,并使用 src/server.ts
设置小型快速服务器,我能够使以下代码正常工作。
app.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { ExpressAdapter } from '@nestjs/platform-express';
import { AppModule } from './app.module';
const bootstrap = async (express: Express.Application) => {
const app = await NestFactory.create(AppModule, new ExpressAdapter(express));
await app.init();
return app;
}
@Injectable()
export class AppMiddleware implements NestMiddleware {
constructor(private expressInstance: Express.Application) {}
use(req: any, res: any, next: () => void) {
console.log('In Nest middleware');
return bootstrap(this.expressInstance);
}
}
app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
server.ts
import * as express from 'express';
import { AppMiddleware } from './app.middleware';
const app = express();
app.use((req, res, next) => {
const nest = new AppMiddleware(app).use(req, res, next);
nest.then(() => {
next();
}).catch(err => {
console.log(JSON.stringify(err));
next();
});
});
app.listen(3000, () => {
console.log('Listening on port 3000');
});
构建命令
npm run build
# mapped to nest build
启动命令
node dist/server.js
测试命令
▶ curl http://localhost:3000
Hello World!
控制台日志
Listening on port 3000
In Nest middleware
[Nest] 24235 - 02/18/2020, 8:05:44 PM [NestFactory] Starting Nest application...
[Nest] 24235 - 02/18/2020, 8:05:44 PM [InstanceLoader] AppModule dependencies initialized +15ms
[Nest] 24235 - 02/18/2020, 8:05:44 PM [RoutesResolver] AppController {/}: +3ms
[Nest] 24235 - 02/18/2020, 8:05:44 PM [RouterExplorer] Mapped {/, GET} route +2ms
[Nest] 24235 - 02/18/2020, 8:05:44 PM [NestApplication] Nest application successfully started +2ms
记住几点:
1) 使用这种方法,除非您缓存您的 Nest 服务器,否则您 将 为每个请求构建一个新的 Nest 服务器,这只会随着您的成长而减慢您的项目在 Nest 方面。
2) 您可以将现有的快速服务器传递给 ExpressAdapter
,就像您在现有代码中部分执行的那样,并改为从 Nest app.listen()
函数启动服务器。只需确保删除任何错误处理中间件,因为它会开始与 Nest 处理响应的方式发生冲突。您应该将这些函数移至 ExceptionFilters。
3) app.middleware
中的错误之一是您不仅在每次调用时创建了一个新的 Nest 实例,而且还创建了一个新的 express 实例,这确实会使节点服务器感到困惑。
4) 如果您想知道,作为 [Object object]
出现的错误是一个标准的 Express 错误 Cannot GET /
。不知道为什么它被奇怪地序列化了,但是 catch 中的 JSON.stringify()
帮助解决了它。
总的来说,我不推荐这种方法但是它是可行的。
我知道这不是问题的确切答案,但我只想留下一个使用这个中间件的例子。
就我的上下文而言,我认为将所有内容都放在巢中是可以的,而不是将巢放在快递中。
我需要把我所有的标准快递应用程序,与节点一起工作,没有特殊条件,只需加入 2,这就是我的场景。
我只是把全局设置,比如 body-parser 和 dotenv 放在我的主文件中。
src/main.ts
import dotenv from 'dotenv'
import bodyParser from 'body-parser'
import { useExpress } from './workspaces/poc/server'
import { TodoModule } from './workspaces/todo/todo.module'
import { NestFactory } from '@nestjs/core';
// was in src/workspaces/my-legacy-app/server.ts
dotenv.config()
async function bootstrap() {
const app = await NestFactory.create(TodoModule);
app.use(bodyParser.json());
// was in src/workspaces/my-legacy-app/server.ts
// also did not know how to resolve the issue of types, so use "any"
useExpress(app.getHttpAdapter() as any)
await app.listen(3000,() => {
console.info(`App runnning on port: ${3000}`)
});
}
bootstrap();
我的旧遗留主文件
src/workspaces/legacy-app/server.ts
import { validatorMiddleware } from './middlewares/validator.middleware'
import { logMiddleware } from './middlewares/log.middleware'
import { userRouter } from './routes/user.route'
import { Express } from 'express'
export function useExpress(server: Express){
server.use(validatorMiddleware)
server.use(logMiddleware)
server.use('/user', userRouter)
// commented because the server will go up here more, but just to show that it was the same way as in express
// server.listen(
// process.env.PORT,
// () => console.log(`Server is running on port ${process.env.PORT ?? 3000}`)
// )
}
@Etienne 你的 bootstrap
功能实际上很好,你可以直接在 express-app.ts
中使用它。优点:
- 每个请求都没有新的 Nest 实例
- 每个快递应用独立配置
app.middleware.ts
import {NestFactory} from '@nestjs/core';
import {AppModule} from './app.module';
import {ExpressAdapter} from '@nestjs/platform-express';
import express from 'express';
export const bootstrap = async () => {
const expressApp = express();
const adapter = new ExpressAdapter(expressApp);
const app = await NestFactory.create(AppModule, adapter);
await app.init();
return app;
};
快递-app.ts
import express from 'express';
import { bootstrap } from './app.middleware';
const app = express();
const PORT = process.env.PORT || 3000;
bootstrap().then(expressApp => {
app.use(expressApp);
app.listen(PORT, () => {
console.log(`app running on port ${PORT}`);
});
});
我有一个 Nestjs 应用程序(一个 Rest API),我想将其导入另一个节点模块,作为一个简单的 Express 中间件(不是 Nest 中间件)。其实我还是没法让它工作。
// main.ts
// => The main file of my Nest app, this one is working properly.
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
// app.middleware.ts
import {Injectable, NestMiddleware} from '@nestjs/common';
import {NestFactory} from '@nestjs/core';
import {AppModule} from './app.module';
import {ExpressAdapter} from '@nestjs/platform-express';
import express, {Request, Response} from 'express';
const bootstrap = async () => {
const expressApp = express();
const adapter = new ExpressAdapter(expressApp);
const app = await NestFactory.create(AppModule, adapter);
await app.init();
return app;
};
@Injectable()
export class AppMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: Function) {
return bootstrap();
}
}
// express-app.ts
// => Here I'm trying to load my app through a simple Express middleware, but it doesn't works.
import express from 'express';
import { AppMiddleware } from './app.middleware';
const app = express();
const PORT = process.env.PORT || 3000;
app.use((req, res, next) => {
const app = new AppMiddleware().use(req, res, next);
app.then(next);
});
app.listen(PORT, () => {
console.log(`app running on port ${PORT}`);
});
当 运行从 main.ts
连接我的应用程序时,它工作正常(所有路由都在工作,我得到了正确的数据)。但是,当我尝试通过 express-app.ts
运行 应用程序时,所有路由似乎都在工作(它们显示在终端中),但在任何情况下我都没有返回 JSON 对象我收到此错误:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>[object Object]</pre>
</body>
</html>
嵌套组件版本:
- @nestjs/common: "^6.10.14"
- @nestjs/core: "^6.10.14"
- @nestjs/platform-express: "^6.10.14"
- express: "^4.16.4"
虽然我不容忍将 Nest 本身用作中间件,但这是可能的。使用 nest new express-server -p npm
的基本设置来创建新的 NestJS 应用程序,并使用 src/server.ts
设置小型快速服务器,我能够使以下代码正常工作。
app.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { ExpressAdapter } from '@nestjs/platform-express';
import { AppModule } from './app.module';
const bootstrap = async (express: Express.Application) => {
const app = await NestFactory.create(AppModule, new ExpressAdapter(express));
await app.init();
return app;
}
@Injectable()
export class AppMiddleware implements NestMiddleware {
constructor(private expressInstance: Express.Application) {}
use(req: any, res: any, next: () => void) {
console.log('In Nest middleware');
return bootstrap(this.expressInstance);
}
}
app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
server.ts
import * as express from 'express';
import { AppMiddleware } from './app.middleware';
const app = express();
app.use((req, res, next) => {
const nest = new AppMiddleware(app).use(req, res, next);
nest.then(() => {
next();
}).catch(err => {
console.log(JSON.stringify(err));
next();
});
});
app.listen(3000, () => {
console.log('Listening on port 3000');
});
构建命令
npm run build
# mapped to nest build
启动命令
node dist/server.js
测试命令
▶ curl http://localhost:3000
Hello World!
控制台日志
Listening on port 3000
In Nest middleware
[Nest] 24235 - 02/18/2020, 8:05:44 PM [NestFactory] Starting Nest application...
[Nest] 24235 - 02/18/2020, 8:05:44 PM [InstanceLoader] AppModule dependencies initialized +15ms
[Nest] 24235 - 02/18/2020, 8:05:44 PM [RoutesResolver] AppController {/}: +3ms
[Nest] 24235 - 02/18/2020, 8:05:44 PM [RouterExplorer] Mapped {/, GET} route +2ms
[Nest] 24235 - 02/18/2020, 8:05:44 PM [NestApplication] Nest application successfully started +2ms
记住几点:
1) 使用这种方法,除非您缓存您的 Nest 服务器,否则您 将 为每个请求构建一个新的 Nest 服务器,这只会随着您的成长而减慢您的项目在 Nest 方面。
2) 您可以将现有的快速服务器传递给 ExpressAdapter
,就像您在现有代码中部分执行的那样,并改为从 Nest app.listen()
函数启动服务器。只需确保删除任何错误处理中间件,因为它会开始与 Nest 处理响应的方式发生冲突。您应该将这些函数移至 ExceptionFilters。
3) app.middleware
中的错误之一是您不仅在每次调用时创建了一个新的 Nest 实例,而且还创建了一个新的 express 实例,这确实会使节点服务器感到困惑。
4) 如果您想知道,作为 [Object object]
出现的错误是一个标准的 Express 错误 Cannot GET /
。不知道为什么它被奇怪地序列化了,但是 catch 中的 JSON.stringify()
帮助解决了它。
总的来说,我不推荐这种方法但是它是可行的。
我知道这不是问题的确切答案,但我只想留下一个使用这个中间件的例子。
就我的上下文而言,我认为将所有内容都放在巢中是可以的,而不是将巢放在快递中。 我需要把我所有的标准快递应用程序,与节点一起工作,没有特殊条件,只需加入 2,这就是我的场景。
我只是把全局设置,比如 body-parser 和 dotenv 放在我的主文件中。
src/main.ts
import dotenv from 'dotenv'
import bodyParser from 'body-parser'
import { useExpress } from './workspaces/poc/server'
import { TodoModule } from './workspaces/todo/todo.module'
import { NestFactory } from '@nestjs/core';
// was in src/workspaces/my-legacy-app/server.ts
dotenv.config()
async function bootstrap() {
const app = await NestFactory.create(TodoModule);
app.use(bodyParser.json());
// was in src/workspaces/my-legacy-app/server.ts
// also did not know how to resolve the issue of types, so use "any"
useExpress(app.getHttpAdapter() as any)
await app.listen(3000,() => {
console.info(`App runnning on port: ${3000}`)
});
}
bootstrap();
我的旧遗留主文件
src/workspaces/legacy-app/server.ts
import { validatorMiddleware } from './middlewares/validator.middleware'
import { logMiddleware } from './middlewares/log.middleware'
import { userRouter } from './routes/user.route'
import { Express } from 'express'
export function useExpress(server: Express){
server.use(validatorMiddleware)
server.use(logMiddleware)
server.use('/user', userRouter)
// commented because the server will go up here more, but just to show that it was the same way as in express
// server.listen(
// process.env.PORT,
// () => console.log(`Server is running on port ${process.env.PORT ?? 3000}`)
// )
}
@Etienne 你的 bootstrap
功能实际上很好,你可以直接在 express-app.ts
中使用它。优点:
- 每个请求都没有新的 Nest 实例
- 每个快递应用独立配置
app.middleware.ts
import {NestFactory} from '@nestjs/core';
import {AppModule} from './app.module';
import {ExpressAdapter} from '@nestjs/platform-express';
import express from 'express';
export const bootstrap = async () => {
const expressApp = express();
const adapter = new ExpressAdapter(expressApp);
const app = await NestFactory.create(AppModule, adapter);
await app.init();
return app;
};
快递-app.ts
import express from 'express';
import { bootstrap } from './app.middleware';
const app = express();
const PORT = process.env.PORT || 3000;
bootstrap().then(expressApp => {
app.use(expressApp);
app.listen(PORT, () => {
console.log(`app running on port ${PORT}`);
});
});