背景

我们在访问淘宝的时候,会看到代码中的js和css文件是通过一次请求获得的,我们知道浏览器一次请求只能并发访问数个资源,这样的处理错输在网络传输层面可以大大节省时间,这里使用的技术就是把css、js等静态资源合并为一个资源。淘宝使用的tengine是基于nginx的web服务器,从11年底开源。所使用的是mod_concat模块,合并多个文件在一个响应报文中。

实战

先查看下当前openresty的版本和配置信息

/usr/local/openresty/nginx/sbin/nginx -V

nginx version: openresty/1.15.8.1
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-23) (GCC)
built with OpenSSL 1.0.1u 22 Sep 2016 (running with OpenSSL 1.0.1e-fips 11 Feb 2013)
TLS SNI support enabled
configure arguments: --prefix=/usr/local/openresty/nginx --with-cc-opt=-O2 --add-module=../ngx_devel_kit-0.3.1rc1 --add-module=../echo-nginx-module-0.61 --add-module=../xss-nginx-module-0.06 --add-module=../ngx_coolkit-0.2 --add-module=../set-misc-nginx-module-0.32 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.08 --add-module=../srcache-nginx-module-0.31 --add-module=../ngx_lua-0.10.15 --add-module=../ngx_lua_upstream-0.07 --add-module=../headers-more-nginx-module-0.33 --add-module=../array-var-nginx-module-0.05 --add-module=../memc-nginx-module-0.19 --add-module=../redis2-nginx-module-0.15 --add-module=../redis-nginx-module-0.3.7 --add-module=../rds-json-nginx-module-0.15 --add-module=../rds-csv-nginx-module-0.09 --add-module=../ngx_stream_lua-0.0.7 --with-ld-opt=-Wl,-rpath,/usr/local/openresty/luajit/lib --user=www --group=www --with-http_stub_status_module --with-http_sub_module --with-http_ssl_module --with-http_v2_module --with-http_gunzip_module --with-http_realip_module --with-http_geoip_module --with-pcre --with-file-aio --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module

下载最新淘宝的nginx-http-concat模块

cd /root git clone git://github.com/alibaba/nginx-http-concat.git

下载对应版本的openresty

注意不需要执行gmake install,执行gmake install是覆盖安装

wget https://openresty.org/download/openresty-1.15.8.1.tar.gz

tar -xzvf openresty-1.15.8.1.tar.gz

cd openresty-1.15.8.1

#配置 最后新增 --add-module=../nginx-http-concat

./configure --prefix=/usr/local/openresty/nginx \
--with-cc-opt=-O2 --add-module=../ngx_devel_kit-0.3.1rc1 \
--add-module=../echo-nginx-module-0.61 --add-module=../xss-nginx-module-0.06 \
--add-module=../ngx_coolkit-0.2 --add-module=../set-misc-nginx-module-0.32 \
--add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.08 \
--add-module=../srcache-nginx-module-0.31 --add-module=../ngx_lua-0.10.15 \
--add-module=../ngx_lua_upstream-0.07 --add-module=../headers-more-nginx-module-0.33 \
--add-module=../array-var-nginx-module-0.05 --add-module=../memc-nginx-module-0.19 \
--add-module=../redis2-nginx-module-0.15 --add-module=../redis-nginx-module-0.3.7 \
--add-module=../rds-json-nginx-module-0.15 --add-module=../rds-csv-nginx-module-0.09 \
--add-module=../ngx_stream_lua-0.0.7 --with-ld-opt=-Wl,-rpath,/usr/local/openresty/luajit/lib \
--user=www --group=www --with-http_stub_status_module --with-http_sub_module --with-http_ssl_module \
--with-http_v2_module --with-http_gunzip_module --with-http_realip_module --with-http_geoip_module \
--with-pcre --with-file-aio --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module \
--add-module=../nginx-http-concat

gmake

#注意不需要执行gmake install,执行gmake install是覆盖安装

发现上面这个原来的配置参数,很多用到了相对目录 “--add-module=../" ,但是自己的目录上层目录并没有这些模块的文件夹,一开始想着是不是要去挨个下载,咨询了很多地方也没有好的答案,于是自己去github上把各个模块对应的版本都下载下来,放到了上层目录中,用上面这个命令configure,结果各种报错:

multiple definition of `ngx_http_rds_csv_output_more_field_data'

表示add-module中的已经自动包含,不需要add-module主动指定。

正确的做法,根本不用下载各个模块,因为执行configure的时候已经生成了对应的模块目录。

目录:/root/openresty-1.15.8.1/build/

./configure --prefix=/usr/local/openresty/nginx \
--with-cc-opt=-O2 --with-ld-opt=-Wl,-rpath,/usr/local/openresty/luajit/lib \
--user=www --group=www --with-http_stub_status_module --with-http_sub_module --with-http_ssl_module \
--with-http_v2_module --with-http_gunzip_module --with-http_realip_module --with-http_geoip_module \
--with-pcre --with-file-aio --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module \
--add-module=../nginx-http-concat

#注意不需要执行gmake install,执行gmake install是覆盖安装

gmake

cd build/nginx-1.15.8/objs/ && cp nginx /usr/local/openresty/nginx/sbin/nginx.new

#找到原来的nginx执行命令
ps -ef|grep nginx|grep master

#原来的命令是 /usr/local/openresty/bin/openresty -c /usr/local/openresty/nginx/conf/nginx.conf
#咱们用新构建的nginx测试下,加上 -t测试
./nginx.new -c /usr/local/openresty/nginx/conf/nginx.conf -t
nginx: [alert] could not open error log file: open() "/usr/local/openresty/nginx/nginx/logs/error.log" failed (2: No such file or directory)

#发现多了一层nginx目录,看起来是configure的时候目录多了一个,重新来一遍

gmake clean

# --prefix 参数减少一个nginx目录

./configure --prefix=/usr/local/openresty \
--with-cc-opt=-O2 --with-ld-opt=-Wl,-rpath,/usr/local/openresty/luajit/lib \
--user=www --group=www --with-http_stub_status_module --with-http_sub_module --with-http_ssl_module \
--with-http_v2_module --with-http_gunzip_module --with-http_realip_module --with-http_geoip_module \
--with-pcre --with-file-aio --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module \
--add-module=../nginx-http-concat

#注意不需要执行gmake install,执行gmake install是覆盖安装

gmake

cd build/nginx-1.15.8/objs/ && cp nginx /usr/local/openresty/nginx/sbin/nginx.new -f

cd /usr/local/openresty/nginx/sbin/ && ./nginx.new -c /usr/local/openresty/nginx/conf/nginx.conf -t

#输出如下信息,标识构建成功

nginx: the configuration file /usr/local/openresty/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/openresty/nginx/conf/nginx.conf test is successful

备份老的nginx文件、覆盖最新的文件

mv /usr/local/openresty/nginx/sbin/nginx /usr/local/openresty/nginx/sbin/nginx.bak
mv /usr/local/openresty/nginx/sbin/nginx.new /usr/local/openresty/nginx/sbin/nginx
/usr/local/openresty/nginx/sbin/nginx -V

#输出如下信息,那些相对目录的模块也都存在,说明没有错误
nginx version: openresty/1.15.8.1
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-23) (GCC)
built with OpenSSL 1.0.1e-fips 11 Feb 2013
TLS SNI support enabled
configure arguments: --prefix=/usr/local/openresty/nginx --with-cc-opt='-O2 -O2' --add-module=../ngx_devel_kit-0.3.1rc1 \
--add-module=../echo-nginx-module-0.61 --add-module=../xss-nginx-module-0.06 --add-module=../ngx_coolkit-0.2 \
--add-module=../set-misc-nginx-module-0.32 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.08 \
--add-module=../srcache-nginx-module-0.31 --add-module=../ngx_lua-0.10.15 --add-module=../ngx_lua_upstream-0.07 \
--add-module=../headers-more-nginx-module-0.33 --add-module=../array-var-nginx-module-0.05 --add-module=../memc-nginx-module-0.19 \
--add-module=../redis2-nginx-module-0.15 --add-module=../redis-nginx-module-0.3.7 --add-module=../rds-json-nginx-module-0.15 \
--add-module=../rds-csv-nginx-module-0.09 --add-module=../ngx_stream_lua-0.0.7 \
--with-ld-opt='-Wl,-rpath,/usr/local/openresty/luajit/lib -Wl,-rpath,/usr/local/openresty/luajit/lib' \
--user=www --group=www --with-http_stub_status_module --with-http_sub_module --with-http_ssl_module \
--with-http_v2_module --with-http_gunzip_module --with-http_realip_module --with-http_geoip_module --with-pcre \
--with-file-aio --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module \
--add-module=/root/openresty-1.15.8.1/../nginx-http-concat --with-stream --with-stream_ssl_preread_module

#重启nginx
/usr/local/openresty/bin/openresty -c /usr/local/openresty/nginx/conf/nginx.conf -s reload

concat配置说明:

使用​​??​​拼接多个文件

​https://www.phpmianshi.com/??style1.css,style2.css,foo/style3.css​

如果有第三个问号,则表示版本号

​https://www.phpmianshi.com/??style1.css,style2.css,foo/style3.css?v=102234​

concat

语法:concat [on|off]

默认:off

配置段:http, server, location

作用:允许在给定的配置段中进行串联

concat_types

语法:concat_types MIME types

默认:text/css application/x-javascript

配置段:http, server, location

作用:定义可以在给定配置段中串联的MIME类型。

concat_unique

语法:concat_unique [on|off]

默认:on

配置段:http, server, location

作用:定义是否只能串联给定MIME类型的文件,或者可以串联多个MIME类型。

concat_max_files

语法:concat_max_files编号

默认:10

配置段:http,服务器,位置

作用:定义在给定配置段中可以串联的最大文件数。

concat_delimiter

合并后的文件内容分隔符,用于区分不同文件的内容

concat_ignore_file_error

是否忽略404或403错误,选项:on | off,默认:off

配置concat配置文件,并再次重启nginx(最好是kill掉完全重启,否则有可能不生效

server {
listen 80;
server_name www.phpmianshi.com;
index index.php;
root /data/nginx/www/www.phpmianshi.com;


location ~ [^/]\.php(/|$) {
try_files $uri =404;
fastcgi_pass unix:/tmp/php-cgi.sock;
fastcgi_index index.php;
include fastcgi.conf;
}

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
expires 30d;
}

location ~ .*\.(js|css)?$ {
expires 12h;
}

location / {
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=$1 last;
break;
}
}
concat on;
concat_max_files 20;
concat_unique off;
concat_types text/css application/javascript;

access_log /data/nginx/logs/access.log json;
}

测试

网站根目录写3个测试文件

#test1.js console.log("11"); #test2.js console.log("22"); #test.html <html> <head> <script type="text/javascript" src="./??test1.js,test2.js"> </script> </head> <body>   这里是文档的主体 ... ... </body> </html>

访问一下  ​​www.phpmianshi.com/test.html​​ ,控制台输出  11  22 ,看network网络请求,只有一次请求,说明配置完成

注意事项

--add-module=build/ngx_stream_lua-0.0.7不需要加,因为:

ngx_stream_lua_module is already enabled in OpenResty by default. Your linker errors clearly indicate that. You should remove the option --add-module=build/ngx_stream_lua-0.0.7.

官方git issue回复:

​https://github.com/openresty/openresty/issues/507​

multiple definition of `ngx_http_rds_csv_output_more_field_data':表示add-module中的已经自动包含,不需要add-module主动指定。