http-proxy-middleware的nodejs组件通常用来代理转发请求,那么在使用过程中遇到过哪些问题呢?
这篇文章不是 http-proxy-middleware 的使用教程,关于如何使用,还请参考官方教程。主要是说下自己之前使用时的注意事项。
1. 无法继续流转路由
如我们在使用 express 等框架时,会声明多个路由的,有的路由是用来处理业务逻辑,有的是收集相关信息,有的是用作拦截器等。
COPYJAVASCRIPT
import { createProxyMiddleware } from 'http-proxy-middleware'; import express from 'express'; const app = express(); app.use('*', createProxyMiddleware()); app.use('*', () => { console.log('after createProxyMiddleware'); // 无法输出 }); const port = Number(process.env.PORT) || 3001; const ip = process.env.IP || '127.0.0.1'; app.listen(port, ip, () => { const msg = `[server]: Server is running at http://${ip}:${port}`; console.log(msg); });
若上面 ↑ 的代码,在对*
进行拦截请求后,后续的路由服务将不再执行。因此对该路由的一些处理,应当放在 http-proxy-middleware
的前面。
我们从源码 ↓ 中就可以看到,createProxyMiddleware()返回的是一个 middleware 方法,即对路由的处理方法:
COPYJAVASCRIPT
// https://github.com/chimurai/http-proxy-middleware/blob/35ac1dbd29ff0953f978373dd6add081819087de/src/index.ts#L4 export function createProxyMiddleware(options: Options): RequestHandler { const { middleware } = new HttpProxyMiddleware(options); return middleware; }
而在 middlware 的方法 ↓ 中可以看到,若代理过程是正常的,则不会再执行next()
的逻辑。
COPYJAVASCRIPT
// https://github.com/chimurai/http-proxy-middleware/blob/35ac1dbd29ff0953f978373dd6add081819087de/src/http-proxy-middleware.ts#L40 export class HttpProxyMiddleware { public middleware: RequestHandler = async (req, res, next?) => { if (this.shouldProxy(this.proxyOptions.pathFilter, req)) { try { const activeProxyOptions = await this.prepareProxyRequest(req); debug(`proxy request to target: %O`, activeProxyOptions.target); this.proxy.web(req, res, activeProxyOptions); } catch (err) { next && next(err); } } else { next && next(); } } }
因此,后续的路由不会再接收请求。
2. onProxyRes 无法处理 content-length 为 0 的数据
我们可以在 onProxyRes 中对获取到的数据进行二次处理,然后再返回。如官方给到的样例intercept-and-manipulate-responses,将 Hello 替换为 GoodBye:
COPYJAVASCRIPT
const { createProxyMiddleware, responseInterceptor } = require('http-proxy-middleware'); const proxy = createProxyMiddleware({ /** * IMPORTANT: avoid res.end being called automatically **/ selfHandleResponse: true, // res.end() will be called internally by responseInterceptor() /** * Intercept response and replace 'Hello' with 'Goodbye' **/ on: { proxyRes: responseInterceptor(async (responseBuffer, proxyRes, req, res) => { const response = responseBuffer.toString('utf8'); // convert buffer to string return response.replace('Hello', 'Goodbye'); // manipulate response and return the result }), }, });
但是,若代理转发地址返回的数据,response header 中,不存在content-length
字段,或者该字段的值为 0。则 onProxyRes 中的 responseBuffer 为空,无法处理处理数据。
如一些 CDN 或者 COS 上的数据,他为了快速响应,或者使用了 chunked 编码(transfer-encoding: chunked),在返回数据时,通常没有 content-length 这个字段。