其实商城项目的网页端,观察京东,淘宝他们有很多活动页面或者商品详情页,推广力度很多,流量也就比较多,通常一个页面很大很大,整个网页内容也很多,单纯考虑从webserver到走进php,java连接数据库等等读取数据拼装,再渲染视图输出到浏览器,整个过程下来,并发不大的情况还好,一大起来的就会性能大大的降低。

对于中小型项目,解决的方案肯定没有淘宝京东的方案多。

于是就要想解决优化的方案,像商品详情页有商品相关的静态数据,同时掺杂着一些评论,购买数量等等的动态数据,其实可以把整个网页动静分离,动态数据走接口,静态数据直接gzip压缩存进缓存,通过Openresty在nginx层面通过lua直接读取就输出,然后浏览器自动解压gzip。由于页面数据是压缩了的可以节省网络IO,大大提升页面的加载速度。但是像一些活动页面,动态数据可能没有那么多,改动商品相关的价格库存…等等改动那么频繁,其实可以直接扔进CDN,动态数据也走接口。

下面来看下PHP的几个GZIP压缩相关的函数,都是基于ZLIB库。

gzcompress gzdeflate gzencode函数的区别在于它们压缩的数据格式不同:

gzcompress使用的是ZLIB格式;

gzdeflate使用的是纯粹的DEFLATE格式;

gzencode使用的是GZIP格式;

但是有一点是相同的,它们压缩数据时都使用了DEFLATE压缩算法(理论上ZLIB和GZIP格式可以使用其他的压缩算法,但是目前实践中只使用DEFLATE算法),ZLIB和GZIP只不过是在DEFLATE的基础之上加了一些头部和尾部而已。

顺便提一下,HTTP协议中的Content-Encoding: deflate使用的是ZLIB格式而不是纯DEFLATE格式。

通过测试发现,gzencode和gzdeflate浏览器可以自动解压出来,前提是:http的请求头里面有accept-encoding:gzip, deflate,说明方案是可行的,但是对于一些浏览器可能不支持自动解压,所以需要判断下请求头,如果不支持,就需要lua解压之后再输出。

既然使用Openresty就在社区搜索了下。
lua的zlib库有两个:
lua-zlib
–通过LuaJIT的FFI库来包装ZLIB模块

选择的是:lua-zlib

lua输出判断函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
local function echoPage(index_page)
--如果index_page=nil 就继续让nginx执行下一阶段,走进php让php自己处理
if not index_page then
ngx.exit(ngx.OK)
end
local accept_encoding_table = ngx.req.get_headers()
local accept_encoding = accept_encoding_table["accept-encoding"]
local need_uncompress = 0
if accept_encoding ~= nil and #accept_encoding>0 then
local begin,stop = ngx.re.find(accept_encoding,'gzip')
if begin ~= nil then
need_uncompress = 0
else
need_uncompress = 1
end
else
need_uncompress = 1
end
if need_uncompress == 1 then
local zlib = require "zlib"
local stream = zlib.inflate()
local inflated,stream_eof,bytes_in,bytes_out = stream(res)
ngx.say(inflated)
else
ngx.header["Content-Encoding"] = "gzip"--避免Nginx再去压缩,需要发送一个响应头,告诉Nginx是一个gzip压缩的
ngx.send_headers()
ngx.say(res)
end
end

注释:

1
2
ngx.exit(ngx.OK)--因为openresty有执行阶段这一个说法,是告诉openresty执行下一阶段
ngx.exit(200)--意思是直接返回200,不再向下执行。也可以是其他的http状态码。