需要反向代理访问某个网站(upstream.com),由于需要动态替换反向代理页面中的链接地址,因此使用sub_filter,但发现未替换成功。认为是响应结果gzip导致的,设置 proxy_set_header Accept-Encoding ” 或 proxy_http_version 1.0 ,sub_filter依然不生效。
按照《Nginx反向代理使用的一些坑》的经验,应该是上游网站强制返回gzip压缩过的内容。在使用文中提到的“与上游服务器连接依然启用gzip压缩,但在调用sub_filter前先解压缩,然后再做替换操作”几种方法时候,发现一些新的问题及注意事项,作为《Nginx反向代理使用的一些坑》的补充说明。
1、使用Nginx ngx_http_gunzip_module
proxy_pass https://upstream.com/; gunzip on; sub_filter 'upstream.com' 'mydomain.com'; sub_filter_once off;
使用以上代码,发现一个奇怪现象,有时候能够替换成功,有时候不行,现象随机,怀疑是gunzip与sub_filter并非串行执行的。
在 https://www.mail-archive.com/[email protected]/msg1313433.html 发现一个回答,提到gunzip on 需要配合 gzip_disable “.” 使用。
(gzip_disable is needed because the author of gunzip had a different use case in mind. Without this option, as an optimization nginx does not decompress the proxied data for a client which breaks the substitution filter.)
尝试gzip_disable “.” 后,发现确实有效。
也即:
proxy_pass https://upstream.com/; gunzip on; gzip_disable "."; sub_filter 'upstream.com' 'mydomain.com'; sub_filter_once off;
2、做两次proxy_pass
基本思路:
a、mydomain.com server 通过unix socket将请求proxy_pass发送给监听server
b、监听unix socket的server向上游upstream发起反向代理请求,请求为gzip on(proxy_set_header Accept-Encoding gzip;)
c、监听unxi socket的server对请求结果gunzip,将gunzip结果回复给mydomain.com server
d、在mydomain.com server对响应结果调用sub_filter替换
server { listen unix:/var/run/nginx-gunzip.sock; location / { proxy_pass https://upstream.com ; gunzip on; proxy_set_header Host "upstream.com"; proxy_set_header Referer "https://upstream.com"; proxy_set_header User-Agent "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0"; #proxy_http_version 1.1; proxy_set_header Accept-Encoding gzip; proxy_set_header X-Real-IP $remote_addr; #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_connect_timeout 60s; proxy_read_timeout 5400s; proxy_send_timeout 5400s; proxy_buffer_size 64k; proxy_buffers 32 32k; proxy_busy_buffers_size 128k; proxy_ssl_verify off; proxy_ssl_server_name on; } } server { server_name mydomain.com; listen 80 ; listen 443 ssl http2; index index.html index.htm; root /data/wwwroot/mydomain.com; error_page 400 = /400.html; location / { proxy_pass http://unix:/var/run/nginx-gunzip.sock:/; sub_filter_types *; sub_filter 'upstream.com' 'mydomain.com'; sub_filter_once off; } }
值得说明一下,相对于通过http请求,unix socket更为高效,但我用的1.6.1 版本存在重启nginx,不会自动删除创建的unix socket情况(SIGQUIT信号不会删除,SIGTERM会自动删除,参见:https://trac.nginx.org/nginx/ticket/753)。
可以把删除操作放到nginx 的service脚本中。
在Centos中,修改 vi /etc/systemd/system/nginx.service,增加
ExecStartPre=/usr/bin/rm -f /var/run/nginx-gunzip.sock
转载请注明:虚拟号之家 » Nginx反向代理使用的一些坑(续)–gzip/gunzip 与sub_filter的那些事