http请求压缩可减少宽带,提升终端加载速度。像http服务自带的压缩是实时的,虽然可通过缓存减少重复请求压缩次数,实际还是不能有效减少重复压缩相同请求,特别是较大的静态文件。


http压缩协议

HTTP 协议中的数据压缩 - HTTP | MDN (mozilla.org)

浏览器会在每个请求中携带 Accept-Encoding 请求头信息,用于标识支持接收的响应数据体编码格式,比如:

nginx预压缩静态文件_html

http服务器就会选择其中一种编码格式进行返回响应数据体,通过响应头信息 content-encoding 标识,比如:

nginx预压缩静态文件_静态文件_02

浏览器获取到支持的响应编码格式后进行解码处理,然后再响应给请求处理(所有浏览器请求)。


nginx 压缩配置

模块ngx_http_gzip_module (nginx.org)

nginx常用压缩配置是通过gzip模块完成的,配置相对简单,常用配置如下:

# 压缩开关 on 或 off
gzip            on;

# 打开静态压缩,会尝试响应 $request_filename.gz 预压缩文件如果存在直接返回,不存在会尝试 $request_filename 文件并返回
gzip_static  on;

# 最少压缩响应体长度,过小的文件压缩意义不大
gzip_min_length 1000;

gzip_proxied    expired no-cache no-store private auth;

# 指定压缩响应类型,默认:text/html,如果要全部压缩可使用 *
gzip_types      text/plain application/xml;

# 压缩级别: 1~9 级别越大压缩率越高同时CPU开销越大
gzip_comp_level 9;

# 匹配User-Agent头信息包含内容的请求不执行压缩的处理
gzip_disable    "MSIE [1-6]\.";

# 开启响应头信息 Vary: Accept-Encoding 代理时使用
gzip_vary 			on;

注意:不同的静态文件压缩率不一样,一般文本类文件压缩率会高些(比如:html、css、js等文件),像图片、音频、视频类压缩率低些。对于压缩率低的文件不建议配置压缩。


预压缩静态文件

nginx非静态压缩是实时的,并且不会缓存前面的压缩结果(缓存由终端浏览器处理),特别是压缩一个大文件会占用较多的CPU,不利于服务器性能利用。

提前将要请求的静态文件进行压缩(压缩文件名是原文件名加 .gz 后缀,且目录不变),然后通过配置请nginx响应出去即可拦截nginx实时压缩又能实现http压缩功能会大大减少nginx压缩开销。

nginx提供了静态压缩功能,即会尝试请求静态文件的压缩文件,比如: index.html  会尝试请求 index.html.gz 文件,当index.html.gz文件存在则直接按压缩模式响应,否则实时压缩index.html文件再返回


预压缩脚本

预压缩脚本代码:保存文件 gzip.php

<?php

if (!extension_loaded('zlib')) {
    die("请安装 zlib 扩展");
}
if ($argc < 2) {
    die("
批量压缩目录内所有文件,压缩成gzip格式

命令:
    php {$argv[0]} source-dir [target-dir]

参数:
    source-dir          要压缩的目录

说明:
    此脚本用来快速预压缩文件,用于静态压缩http请求静态文件
");
}

$dir = $argv[1];
if (!is_dir($dir)) {
    die('目录不存在:' . $dir);
}
$sourceDir = realpath($dir) . '/';
$count = 0;
foreach (forFile($sourceDir) as $file) {
    $targetFile = $sourceDir . $file . '.gz';
    if (file_exists($targetFile)) {
        unlink($targetFile);
    }
    $gzip = gzopen($targetFile, 'wb9');
    gzwrite($gzip, file_get_contents($sourceDir . $file));
    gzclose($gzip);
    $count++;
}
echo "成功压缩文件:" . $count . PHP_EOL;

function forFile(string $dir, string $prefix = '') {
    foreach (scandir($dir) as $file) {
        if ($file == '.' || $file == '..') {
            continue;
        }
        $path = "$dir/$file";
        if (is_file($path)) {
            yield $prefix . $file;
        } else {
            yield from forFile($path, $prefix . $file . '/');
        }
    }
}

预压缩文件生成

php gzip.php /www/html

重启nginx,打开浏览器验证下预压缩是否成功。(可尝试删除原文件再请求,如果能正常请求说明静态压缩配置成功)

注意:通过nginx指定压缩文件再附加压缩header头信息容易有兼容问题,部分浏览器会屏蔽请求并提示 net::ERR_CONTENT_DECODING_FAILED 错误,比如谷歌浏览器