最近公司前端框架组提了个需求,希望修改response中的一个css文件,去掉一个样式:max-width:1632px;。于是便想到了利用lua。
OpenResty lua编程相关资料
其中Readme要看完,是github上对OpenResty的lua-nginx-module比较全面的介绍。
Nginx处理的几个阶段
此处放上从网上找来的一幅图,
我这里修改response body显然是需要用到body_filter_by_lua*指令。
修改Response Body
修改Response Body的方式总体来说有4种,分别是:
- 1.使用 body_filter_by_lua
指令来实现:http://wiki.nginx.org/HttpLuaModule#body_filter_by_lua 这个支持流式处理。 - 2.使用 ngx.location.capture 发起子请求,然后对子请求的响应体进行全缓冲式修改
3.可以使用 ngx_replace_filter 模块来进行流式正则替换
替换成的目标值可以通过 ngx_lua 模块嵌入一小段 Lua 代码来事先计算好,放置在你自己定义的 nginx 变量中,然后在 replace_filter 指令中直接引用之。比如set_by_lua $my_var ‘… return …’;
replace_filter ‘folderlist=\w+’ ‘folderlist=$my_var’ ‘g’;- 4.使用http_sub_module模块
根据实际的需求,使用第3种,需要先安装sregex library,然后重新编译安装OpenResty,在编译时 ./configure –add-module=/path/to/replace-filter-nginx-module 启用replace-filter-nginx-module模块。
如果使用第4种方式都需要重新编译安装OpenResty,在编译时 –with-http_sub_module 启用http_sub_module模块。
这两种他们都不接受,因为涉及的客户太多。
对于第2种方式,是个比较好的方式,但是使用第二种方式需要增加一个用于子请求的location,相当于大动了配置文件,并且相应的我还得去修改之前写的安装升级脚本,于是最终还是选择了第一种方式。
虽然第2种到第4种的方案不适用于此次的需求,但是我还是尝试了使用下第2种和第4种的方案,并会把相关的脚本和配置贴在下面。
第一种处理办法
lua脚本代码如下:
Nginx相关location配置如下:
但是重载Nginx后发现,这个css样式的响应时间竟然是1.1min,可怕。。。
仔细阅读上面贴出来的OpenResty Readme,发现有这么一段话:
|
|
于是需要修改配置文件,在body_filter_by_lua_file /opt/lua/replace.lua之前就得把header中的 content_length 置为空。
这样重载Nginx,清除缓存重新访问下,发现加载就正常了。
仔细了解了下原因,当代码运行到 body_filter_by_lua 时,HTTP 报头(header)已经发送出去了。如果在之前设置了跟响应体相关的报头,而又在 body_filter_by_lua 中修改了响应体,会导致响应报头和实际响应的不一致。举个简就是说这个例子里上游的服务器返回了 Content-Length 报头,而 body_filter_by_lua* 又修改了响应体的实际大小(因为我删除了一些字符串)。客户端收到这个报头后,按其中的 Content-Length 去处理,顺着一头栽进坑里。由于Nginx 的流式响应,发出去的报头就像泼出去的水,要想修改只能提前进行。这是流式处理常常面对的悖论:要在流的开始输出长度,但又不能在那个时间事先知道流的长度。
对于处理逻辑简单的场景来说,Lua是十分合适的。
第二种处理办法
lua脚本:
Nginx相关配置:
第四种处理办法
需要重新编译安装OpenResty,编译时加入参数 –with-http_sub_module。
Nginx相关配置如下: