Koa下http代理

前言

最近作管理後臺的重構或者說重作. 至於爲何要重構.
隨意的解釋:前端

  1. 是原來寫的人走了.

客觀的解釋:node

  1. 用的人以爲很差用
  2. 維護的人員找不到北

再多一點解釋:react

  1. express + ejs的混合編寫
    • 單獨抽象了Router層, 定義了controller層, service層, 可是強行綁定, 耦合很緊密
    • 中間件過分使用, 本意想簡化操做, 反而編程負擔
    • 服務端定義了渲染模板, 前端又有模板, 額
    • 引入ts, 可是不少都是any, 接口不少都是直接把query或者body參數直接使用, 很是難跟蹤數據
    • views未按照功能分文件夾, 所有在一個文件夾下, 頭暈的厲害
    • 後臺配置不合理, 即便是菜單這種配置也是徹底同樣的幾份
  2. 前端雜亂
    • jquery編寫, 自己並沒有問題, 沒有模塊化, 出現代碼多頁面混用, 一處修改, 可能多頁面出錯
    • 體驗不好, 測試人員和開發人員都不必定能正常操做

額外說兩句, 這裏的express + ejs的項目屬於前端項目, 後臺有不少nodejs編寫的形式微服務的服務.jquery

由於是後臺管理項目, 美觀要求並非那麼高. 個人規劃是.express

基於koa的node中間層編程

  1. 受權管理
  2. ACL管理, 這裏咱們本身編寫的輕量級的權限控制.
  3. 文件上傳(阿里) 和其餘可能須要定製的處理, 好比使用文件批量上傳數據的處理
  4. 請求轉發

前端項目
使用 create-react-app + react-app-rewired + ant + mobx 構建項目,
ant design已經基本夠用, 實際上mobx均可以不用.api

這裏就有兩個項目項目了, 一個ui項目, 一箇中間層api項目.服務器

開發模式下, ui項目是經過dev-server啓動的, 會經過代理轉發請求到中間層api項目, 中間層api項目再轉發到實際的服務. 這一切看起來都很美好, 也沒毛病.session

問題

我隨手拈來, 配置好, 開始請求. 就淚奔了. 請求死活過不去.app

各類中間件嘗試

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打算有時間深刻看一看, 值得擁有.

相關文章
相關標籤/搜索