nodejs中http-proxy使用小结
最近在写xmocker的工具,用于开发前期的mock数据,不可避免的用到了代理的中间件。当然,github上有关于http-proxy封装的中间件。毕竟是自己练手的项目,就自己写了个中间件,方便定制功能。
http-proxy库用于koa中,是使用它的 proxy.web方法。常规的用法是:
proxy.web(req, res, { target: 'http://mytarget.com:8080' }, function(e) { ... });
项目中的要求是将API代理到用户填写的网址上去。Koa提供了req和res,用户提供了网址,这样中间件就很容易写了
function proxyTo({ status }) { return async function (ctx, next) { return next().then(async () => { if (status === undefined || ctx.status === status) { let data try { data = await proxy.web(ctx.req, ctx.res) } catch (e) { if (err) console.log(err) return } } }) } }
设置访问结果为404则进行代理,否则不进行代理。然后在koa的中间件中use这个函数就可以了。
基础应用这样自然就可以了,可是遇到POST的时候就不行了,因为用到了koa-bodyparser,导致post的请求没法发给服务器。在http-proxy的issue中到处找解决办法,终于找到了让req重新stream的方法。
proxy.on('proxyReq', function (proxyReq, req, res, options) { if (req.body) { let bodyData = JSON.stringify(req.body) // incase if content-type is application/x-www-form-urlencoded -> we need to change to application/json proxyReq.setHeader('Content-Type', 'application/json') proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData)) // stream the content proxyReq.write(bodyData) } })
嗯,这样基本就完成了一个Proxy的中间件。
刚开始用起来还不错,至少普通的API都可以转发了。于是试着代理到公司的API系统,网页端也没发现什么问题。然后用fiddler代理安卓客户端,用正则代理链接至自己的服务,出现了乱码。。。客户端用的是okhttp发出的请求,fiddler上看转发回来的json数据明明是正常的,结果在手机上中文就是不正确,都是十六进制代码,根本没解析。仔细对比:编码?都是utf-8,这个没问题。gzip?我明明是用的pipe过去,代码原封不动啊。我试中捕获了所有数据,用gzip解码后,也是正确的,那为什么会出错呢?
和别人交流了好久也没找到问题。没办法,到代码中找找。对于请求的header,发现cookie貌似少了一条,就看看header转发时候怎么处理的。结果发现,header全是进行转换的。issue中有提到set-cookie多条的问题,我这也是这个情况,尝试着看看这个文件改动记录,意外发现了一个Option项 :preserveHeaderKeyCase。
nodejs中header都是小写的形式,所以http-proxy中就进行了转换,将请求全部header转为小写。于是改了了true,这样就不再转换了。然后,客户端正常了!!!哈哈,仔细一看,cookie还是不是多条。算了,先不管cookie了,至少普通登录没啥问题了。
另外加个changeOrigin为true可以防止有些服务器path取的是初始域名,出现404的问题。暂时就这么多啦。proxy插件的地址在:
https://github.com/wenlonghuo/xmocker/blob/master/app/plugin/proxy.js
欢迎试用我的Mock工具:
https://github.com/wenlonghuo/xmocker-cli