Koa下http代理

发布日期:2019-04-07

前言

最近做管理后台的重构或者说重做. 至于为什么要重构.随意的解释:

    是原来写的人走了.

客观的解释:

    用的人觉得不好用维护的人员找不到北

再多一点解释:

    express + ejs的混合编写单独抽象了Router层 定义了controller层 service层 但是强行绑定 耦合很紧密中间件过度使用 本意想简化操作 反而编程负担服务端定义了渲染模板 前端又有模板 额引入ts 但是很多都是any 接口很多都是直接把query或者body参数直接使用 非常难跟踪数据views未按照功能分文件夹 全部在一个文件夹下 头晕的厉害后台配置不合理 即使是菜单这种配置也是完全一样的几份前端杂乱jquery编写 本身并无问题 没有模块化 出现代码多页面混用 一处修改 可能多页面出错体验很差 测试人员和开发人员都不一定能正常操作

额外说两句 这里的express + ejs的项目属于前端项目 后台有很多nodejs编写的形式微服务的服务.

因为是后台管理项目 美观要求并不是那么高. 我的规划是.

基于koa的node中间层

    授权管理ACL管理 这里我们自己编写的轻量级的权限控制.文件上传(阿里) 和其他可能需要定制的处理 比如使用文件批量上传数据的处理请求转发

前端项目使用 create-react-app + react-app-rewired + ant + mobx 构建项目ant design已经基本够用 实际上mobx都可以不用.

这里就有两个项目项目了 一个ui项目 一个中间层api项目.

开发模式下 ui项目是通过dev-server启动的 会通过代理转发请求到中间层api项目 中间层api项目再转发到实际的服务. 这一切看起来都很美好 也没毛病.

问题

我随手拈来 配置好 开始请求. 就泪奔了. 请求死活过不去.

各种中间件尝试

express下面有很好用的http-proxy-middleware 但是koa并没有 koa官方推荐的是koa-proxies 和koa-better-http-proxy 自己搜索发现 koa-proxy下载量和star都还要高一些 于是自己就开始挨个试试 均失败.

开始怀疑是版本问题 查看均是支持的 而且debug确实执行了请求发送 debug进入源码发现 Socket hang up.

自己封装

后来检查源码 其实都是基于http-proxy进行的封装 于是参考别人的代码 自己简单的封装了一个版本 进行debug 结果依旧

koa-connect

后来搜索发现 koa下能使用express的中间件 需要通过转换 这个中间件就是koa-connect 于是进行切换 结果还是失败 心疼

http-proxy 生命周期拦截

接着尝试 在http-proxy的各个生命周期进行拦截 成效也不大 倒是了解了一下http-proxy

x-www-form-urlencoded

我们的接口全部都是post调用的而且接受的数据格式都是x-www-form-urlencoded 偶尔一次发现 使用get居然转发到了服务器 只是提示不允许get调用 其实说明已经能联通 但是post却是过不去. 那就说明问题很可能处在数据传递的格式.

百度bing和google搜索

发现了这篇文章http-proxy-middleware nodejs post请求超时问题 x-www-form-urlencoded我把代码提前了 结果真的是ok了 我的眼泪啊.

但是 不能这样啊 我的auth拦截肯定会先于proxy auth之前肯定还有bodyParser session等中间件 大哥这可不行啊.

继续搜索 edit-post-parameters-prior-to-forwarding-to-a-proxy-target-and-sending-response

onProxyReq(proxyReq req res) { if ( req.method == "POST" && req.body ) { // Add req.body logic here if needed.... // .... // Remove body-parser body object from the request if ( req.body ) delete req.body // Make any needed POST parameter changes let body = new Object() body.filename = "reports/statistics/summary_2016.pdf" body.routeid = "s003b012d002" body.authid = "bac02c1d-258a-4177-9da6-862580154960" // URI encode JSON object body = Object.keys( body ).map(function( key ) { return encodeURIComponent( key ) + "=" + encodeURIComponent( body[ key ]) }).join("&") // Update header proxyReq.setHeader( "content-type" "application/x-www-form-urlencoded" ) proxyReq.setHeader( "content-length" body.length ) // Write out body changes to the proxyReq stream proxyReq.write( body ) proxyReq.end() } }

看到重写了content-type和content-length 我就笑了. 还是自己太天真 没理解好这个onProxyReq方法 于是我也这么重写 再提前其他中间件 就没有问题了.

我真的就能苦笑了 还好解决了问题. 关于http-proxy打算有时间深入看一看 值得拥有.