Mac知道在 Nginx 配置文件里开启了 gzip 和 brotli 两种压缩方式,用来给 css、txt、html 等文本文件进行实时压缩,来减小这些文档的体积,加快访客的访问速度。
近期在 Pingdom Tools 对网站速度进行检测时发现,网站在 Compress component with gzip 这一项上分数很低,提示有可以压缩的文档没有被压缩。经过排查,发现是本站一个名为 main.css 文件。
一、问题现象
main.css 文件是本站后台用来生成覆盖原始样式的一个 css,他并不是一个真实存在的文件,是使用 nginx rewrite 之后的文件,实际执行的是一个 PHP,有了它可以方便在后台添加和重写 css 样式。
奇怪的是,main.css 看起来非常正常, php 也没有报任何错误。但是几乎所有的服务器程序,包括国外一台 nginx proxy cache 和国内的又拍云均不对 main.css 进行压缩,这让我非常疑惑。
二、排查过程
根据 nginx 的压缩规则,他是根据后缀判别文件需不需要压缩,显然,在 nginx 配置里,css 是可以被压缩的,而且,其它实体的 css 文件压缩一切正常。
开始怀疑是 ngx_brotli 这个第三方扩展的原因,怀疑与 Gzip 是否有冲突。禁用掉后,问题依旧。
之后怀疑是 php 输出的问题,检查 php 错误文档,直接访问 rewrite 之前的文件地址 (php文件)发现也没有被压缩,而其它 php文件的输出内容可以正常压缩,初步判定是这个 php 文件的问题。
原因:通过 Chrome 的控制台查看查看输出内容,发现 Content-type 里有些怪异,charset 这个字段出现了两次,经过查阅相关 http header 文档,发现 charset: utf-8 这种写法是错误的,虽然说前面的 text/css 这个类型正确,也能正常被 Chrome 识别为是css,但是由于 charset 写法错误,导致了 nginx 拒绝对这个文件进行压缩。

当然,说起问题来很简单,实际排查花了我几个小时,因为输出的 Content-type 里也包含了 text/css 这个字段,当时根本没有想到后面的charset 字段。我甚至一度怀疑是 Nginx 自身的 Bug。
三、解决方案
修改 php 源码,将 ”:“改为 ”-“,即 Charset-utf-8
由于主题不是我开发的,改了 php header 后主提升机会被覆盖,我是用了 nginx 的第三方 more_header 模块,定点将 mian.css 的 header 强制输出为 content-type:text/css; 这样也临时能解决问题。同时通知主题的作者记得下一个版本更新时候记得修改下内容。
原来一个拼写的小问题会造成后续的麻烦,看来以后向 http header 输出内容时候,一定要谨慎。
一条评论
补充:http header 输出正常之后记得刷新 cdn 的缓存,因为缓存会默认保存 header 的内容。