解决反代时由于headers不规范引发的ERR_HTTP2_PROTOCOL_ERROR问题

杯杯杯杯具 2020-02-12 PM 1358℃ 3条

最近闲来无事整理了一下北洋园PT在各站开的官邀地址,却因在家没有教育网IPv6被六维拒之门外。想到tju的IPv6在19年年末突然恢复了传入连接,就打算搭一个六维的反代玩玩。

当然,六维的反代搭的也是十分流畅,几乎没有遇到什么问题;搭完六维的之后想顺手把CUGB也反代一下,这样在家就没有不能上的教育网PT了(写文章的时候突然意识到蝴蝶也没法上,回头再说吧hhh),然而在部署完访问时就出现了如下问题:
ERR_HTTP2_PROTOCOL_ERROR
之所以会出现HTTP2相关,是因为我在家没法直连tju的IPv6(别问为啥,我也不知道),所以套了Cloudflare(尽管回源速度感人,但也没什么办法)。查了查,白嫖套餐好像没法修改默认的HTTP2配置,改这里看来是走不通了。

虽然之前在MoeCat就见到过这个问题,但是怎么都想不起来当时具体是什么原因,怎么解决的了。一番查找后找到了Chrome自带的Network Log工具 chrome://net-export/ ,通过它记录了访问反代时的网络日志,并使用NetLog viewer打开了日志。在Events选项卡中过滤了一下后,看到了11条相关事件。
Events
首先自然是ID26123这个红底的URL_REQUEST引发了我的注意(对红色的敏感,笑),在这里我们可以看到在t=5074时抛出了ERR_HTTP2_PROTOCOL_ERROR这个错误,而这一帧的描述是HTTP_TRANSACTION_READ_HEADERS

emmmm,读headers时为什么会出错呢,抱着这个疑问继续在这些条目中寻找,在最后一条类型为HTTP2_SESSIONID26131中,我们找到了t=5074时的完整报错,即Invalid character in header name.
Screenshot_20200212_214454.png
简单来说,在header_name中不应该出现末尾的空格,即location 应改为location,否则Chrome会抛出错误HTTP2_SESSION_RECV_INVALID_HEADER

问题找到了,但怎么解决却令我有点为难,毕竟这只是个反代,我也不可能去修改CUGB的源码来解决这个问题。查NGINX的文档也并没有什么简单的例如正则等方式修改response的headers。网上普遍的方式都是用lua,于是装上openresty开始撸人生第一段lua代码。

主要参考了NGINX Lua Directives,还有菜鸟教程的Lua教程一把梭。

function trim(s)
  return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
end

local headers, err = ngx.resp.get_headers()
for key, value in pairs(headers) do
    local trimed_key = trim(key)
    if (trimed_key ~= key) then
        ngx.header[key] = nil
        ngx.header[trimed_key] = value
    end
end

然后随手丢一下nginx的配置,其实我也不确定我各项配的是否最优,欢迎指出。

    server {
        listen [::]:443 ssl;

        ssl_certificate path/to/fullchain.pem;
        ssl_certificate_key path/to/privkey.pem;

        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;
        ssl_session_tickets off;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
        ssl_prefer_server_ciphers on;

        root html;

        server_name REVERSE_PROXY_URL;
        access_log  logs/cugb_access.log;
        error_log logs/cugb_error.log;

        location / {
        sub_filter "http://pt.cugb.edu.cn" "https://REVERSE_PROXY_URL";
        sub_filter "pt.cugb.edu.cn" "REVERSE_PROXY_URL";
        sub_filter_once off;
        sub_filter_types *;
 
        #Proxy Settings
        proxy_redirect     off;
        proxy_set_header Host pt.cugb.edu.cn;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Referer http://pt.cugb.edu.cn/;
        proxy_set_header Accept-Encoding "";
        
        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_cache off;
        proxy_max_temp_file_size 0;
        
        header_filter_by_lua_file lua/trim_header_keys.lua;
        
        proxy_pass  http://pt.cugb.edu.cn/;
        }
    }

经过如此修改,访问时就完全正常了。

标签: 反代, PT, Lua

非特殊说明,本博所有文章均为博主原创。

评论啦~



已有 3 条评论


  1. 八月
    八月

    我永远喜欢杯具.jpg

    回复 2020-02-13 00:27
  2. marktub
    marktub

    期待大佬可以出一篇讲6v反向代理的文章,本人纯小白很想学习一下!

    回复 2020-03-14 11:17
    1. 杯杯杯杯具
      杯杯杯杯具 博主

      6v反代要用教育网内的机器的(且此机器可以从校外IPv6访问),如果满足上述条件的话其实参考其他反代教程就行,反代的原理基本都是一样的

      回复 2020-03-15 00:06