今天心血来潮,想看看博客的传输压缩做得怎么样。本来以为一切正常,结果 curl 敲完一看,人有点懵。
先交代下背景。我博客的 nginx 配了 gzip,gzip_types 写了这么一串:
gzip_types text/plain text/css text/xml text/javascript
application/x-javascript application/xml+rss
application/json image/svg+xml;
看着挺全的吧?HTML 能压、CSS 能压、连 SVG 都写进去了。我用了好几个月都以为万事大吉。
然后今天试了一下:
curl -sI -H "Accept-Encoding: gzip" https://jiangym.top/js/main.js
返回头只有 content-length,没有 content-encoding: gzip。
我不信邪,试了好几个 JS 文件——main.js、pjax_main.js、aos.js——全部没有压缩头,而且 content-length 跟实际文件大小一模一样。比如 main.js 是 5685 bytes,未压缩就是 5685 bytes。
说明啥?说明这些 JS 文件从建站到现在,一直在裸奔。
为什么会这样?
问题出在 nginx 的 MIME 类型映射上。现代的 nginx 里,.js 文件默认映射的 MIME 类型是 application/javascript,而不是早些年用的 text/javascript 或者 application/x-javascript。
再看我的 gzip_types——
写了 text/javascript,写了 application/x-javascript,就是 没写 application/javascript。
nginx 的 gzip 模块在判断要不要压缩的时候,是按 响应的 Content-Type 匹配的。你配了 text/javascript,但实际返回的是 application/javascript,那对不起,不压缩。
所以这半年来,我的 JS 文件一直都是原封不动地发给客户端。加起来 main.js + pjax_main.js + aos.js + insert_highlight.js + tabs.js,一共大概 21KB。单次请求不算多,但一天几百个请求、一个月下来也被多浪费了好几 MB 的流量。主要是用户体验上,JS 是渲染阻塞资源,大了就白等着。
修复就加一行
| |
把 application/javascript 加进去,nginx -t 验证通过,reload 完事。
再测一下:
curl -sI -H "Accept-Encoding: gzip" https://jiangym.top/js/main.js
返回头多了 content-encoding: gzip,content-length 从 5685 降到了两千多,省了一半以上。
为啥过了半年才发现
这个问题其实很好发现——随便 curl 一下就能看出来。但问题是 谁会没事去查 gzip 配没配对啊。
我每次改 nginx 配置都是加功能:加 444 拦截、加缓存 header、加安全头。性能优化这块,装完 gzip 测了 HTML 能压缩就再也不管了,觉得"配了就行"。标准的装了就不管的心态,跟买了保险不看条款一个德行。
而且说真的,JS 文件也没多大,单个也就几 KB,不压缩大部分人也感觉不出来。但问题不在大小,在态度——你觉得自己做好了,实际上差了一步。
顺带看了下其他文件
既然查了就顺便把别的也看了。CSS 和 HTML 正常压缩,SVG 也正常。图片那些本身就是压缩过的,nginx 不会对 png/jpg/webp 套二次 gzip,因为压了反而可能变大,nginx 默认就不压图片类型,这个是对的。
唯一漏的就 JS,补上了。建站半年才修了这么个小问题,感觉像发现自己裤子上有个洞,虽然不太明显,但知道了就得缝上。
| |
不过 brotli 先不上了,1 核小鸡多一个模块多一份负担。gzip level 6 够用了。
就这样,这半年的 JS 传输欠债,今天还了。