【发布时间】:2020-03-02 17:59:05
【问题描述】:
https://github.com/baumgarb/reverse-proxy-demo 上提供了示例代码。README.md 说明了如何在克隆存储库时重现问题。
我有一个 API 网关和一个返回 todos (TodosAPI) 的下游服务。客户端通过 API Gateway 访问下游服务。
API 网关正在利用 http-proxy-middleware 包来代理请求。有两种实现方式,第 2 种方式不起作用:
1. main.ts 中的全局中间件,在路径 /api/v1/...
这种方法工作得非常好,它代理所有请求到下游服务,无论是什么 http 方法(GET、PUT、...)。
import * as proxy from 'http-proxy-middleware';
app.use(
'/api/v1/todos-api',
proxy({
target: 'http://localhost:8090/api',
pathRewrite: {
'/api/v1/todos-api': ''
},
secure: false,
onProxyReq: (proxyReq, req, res) => {
console.log(
`[Global Functional Middlware]: Proxying ${req.method} request originally made to '${req.originalUrl}'...`
);
}
})
);
2。在路径 /api/v2/... 启动的应用程序模块中注册的 NestMiddleware...
这种方法适用于 GET 请求,但其他 http 方法(如 PUT)会一直“挂起”,并且客户端从未收到任何响应。问题似乎是下游服务中的控制器从未被调用过。
import * as proxy from 'http-proxy-middleware';
export class ReverseProxyMiddleware implements NestMiddleware {
private proxy = proxy({
target: 'http://localhost:8090/api',
pathRewrite: {
'/api/v2/todos-api': ''
},
secure: false,
onProxyReq: (proxyReq, req, res) => {
console.log(
`[NestMiddleware]: Proxying ${req.method} request originally made to '${req.originalUrl}'...`
);
}
});
use(req: Request, res: Response, next: () => void) {
this.proxy(req, res, next);
}
}
并且这个中间件注册如下:
@Module({
imports: [],
controllers: [AppController],
providers: [AppService]
})
export class AppModule implements NestModule {
configure(consumer: import('@nestjs/common').MiddlewareConsumer) {
consumer
.apply(ReverseProxyMiddleware)
.forRoutes({ path: 'v2/todos-api', method: RequestMethod.ALL });
}
}
- 运行
curl -X PUT -H "Content-Type: application/json" -d "{\"id\": 1, \"userId\": 1, \"title\": \"delectus aut autem - v1\", \"completed\": true}" http://localhost:8080/api/v1/todos-api/1运行良好 - 运行
curl -X PUT -H "Content-Type: application/json" -d "{\"id\": 1, \"userId\": 1, \"title\": \"delectus aut autem - v2\", \"completed\": true}" http://localhost:8080/api/v2/todos-api/1时遇到下游服务中的控制器永远不会被调用的问题
NestMiddleware 正在代理请求(我可以看到一条日志行说[NestMiddleware]: Proxying PUT request originally made to '/api/v2/todos-api/1'...),下游服务接收到请求(我可以从日志中看到)。但是下游服务不会调用控制器/动作,最终永远不会返回。
有人知道我在这里做错了什么吗?提前非常感谢!
【问题讨论】:
-
老实说,这并不是真正要发表评论的东西,但这并不是一个真正的答案,所以:我已经尝试调查这个并检查了通过两个代理传入的内容(全局和 Nest 中间件之一)和 reqs 看起来相同。我感觉由于 http-proxy-middleware 包的底层结构以及该中间件的工作原理,存在一些问题。默认情况下,Nest 不一定会处理错误中间件,我感觉它正在以某种方式处理这个问题。这可能需要在 github 存储库中作为问题提出。
-
非常感谢您的回复和透彻的分析。当您说“请求看起来相同”时:您是否检查了下游服务端的传入请求?如果是的话,我想我迷路了。因为如果它们在下游服务方面是相同的,那么我想不出任何解释为什么下游服务中的操作不会被调用。
-
是的,只是在被代理到的服务器上的全局中间件中做了一个简单的
console.log(req),几乎没有发现任何差异。如果是这种情况,我认为中间件会尝试处理某种请求后功能,但由于 Nest 的设置方式而无法处理。有趣的想法是在拦截器而不是中间件中尝试这个,看看它是否在那里工作。 -
这里是一个愚蠢的问题——带有
application/jsoncontent-type 的“除了get”让我认为这是一个cors 问题。也许 Nest 没有处理 cors 错误?你试过用邮递员打 v2 吗? -
不,这里没有 CORS 问题。没有涉及 Web 上下文的客户端会阻止跨域请求。这是一个使用 curl 完成的简单 API 调用。你也可以用 Postman 或者 Insomnia 来测试,和 curl 没什么区别。
标签: middleware nestjs http-proxy-middleware