gzip_static的有效使用

2,483 阅读3分钟

gzip_static的有效使用

聊到前端性能优化,总逃不过 Nginxgzip压缩,那你知道静态压缩 gzip_static吗?以及它的有效使用方式吗?

压缩模式

一般来说, Nginxgzip分为两种模式:

  1. 动态压缩
  2. 静态压缩

动态压缩

动态压缩是指 Nginx服务器在发送前端产物时,消耗自身的资源进行实时压缩,这样即便产物中不存在 .gz结尾的文件,浏览器端也能拿到 gzip格式的前端产物。其一般配置如下:

server {
  gzip on;
  gzip_vary on;
  gzip_min_length 1k;
  gzip_proxied expired no-cache no-store private auth;
  gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml application/javascript;
  gzip_disable "MSIE [1-6]\.";
}

静态压缩

静态压缩会直接将产物中预先压缩过的 .gz文件发送给浏览器,而不再实时压缩文件,如果找不到 .gz文件,将会使用对应的原始文件。

开启

有个前提条件,要保证 Nginx存在 ngx_http_gzip_static_module模块,这个模块默认不开启,需要使用 --with-http_gzip_static_module来激活。

可以使用下面指令查看是否已经激活该模块

nginx -V 2>&1| grep -o http_gzip_static_module
# http_gzip_static_module

http_gzip_static_module

如果不存在则需要在编译时开启

cd nginx-1.20.2
./configure --prefix=/usr/local/nginx --with-http_gzip_static_module
make && make install

Docker

对于 Docker版本的 nginx:alpine则不需要查看这些,接着配置就可以了

一般配置

gzip_static  on;
gzip_proxied expired no-cache no-store private auth;

按照一般的文档,到这里就可以结束了,已经完成静态压缩的配置了。

但是真得有效果吗?我们来试一下

项目演示

使用 vite

示例以 vite来创建,webpack也是可以的

npm create vite@latest my-vue-app -- --template vue
cd my-vue-app
npm install

Gzip配置

webpack可以使用 compression-webpack-plugin,配置不再赘述

安装 vite-plugin-compression插件(用于生成 .gz文件),并修改 vite.config.ts。

// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import viteCompression from 'vite-plugin-compression'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
  	viteCompression({ // 开启 gzip压缩
      deleteOriginFile: true,
    }),
  ],
})

deleteOriginFile选项默认为 false,表示生成 .gz文件后,不会删除源文件。为了测试 Nginxgzip_static是不是直接使用了 .gz文件,我们把 deleteOriginFile设为 true

build

截屏2023-02-22 14.36.07.png

deploy

有了创建产物,就可以开始部署前端服务了,先来看一下现有 Nginx配置。

server {
  listen 80 default_server;
  listen [::]:80 default_server;
  root   /usr/share/nginx/html;

  gzip_static on;
  gzip on;
  gzip_vary on;
  gzip_min_length 1k;
  gzip_proxied expired no-cache no-store private auth;
  gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml application/javascript;
  gzip_disable "MSIE [1-6]\.";

  location / {
    try_files $uri $uri/ /index.html;
    index  index.html index.htm;
  }
}

演示的时候将直接使用 Nginx的方式进行部署,部署步骤不再演示。部署成功就可以直接访问服务了。

问题处理

MIME Type

这时,我们发现页面出现了空白,控制台也出现了报错。

Failed to load module script: Expected a JavaScript module script but the <img src="server" alt="" width="100%" /> responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.

报错的原因是返回头的格式与实际请求的文件格式不相符,点开其中 js的请求,我们可以看到它的 Content-Type变成了 text/html,css文件的 Content-Type也成了 text/html

js返回格式

这就说明目前的 gzip_static并没有发挥作用,没有正确识别文件的格式。那现在就从文件的格式入手解决。加一些 Nginx对文件格式的配置,测试一下,下列两种配置均有效果,但是推荐使用第一种,原因参考下文中 502错误处理。

# 第一种
location ~ \.(js|mjs|json|css|html)$ {
  gzip_static on;
}

# 第二种
location /assets {
  gzip_static on;
}

然后检测 Nginx配置,重启 Nginx

nginx -t
nginx -s reload

刷新页面,就可以看到正常的页面,Response Headers中:

  • js文件 Content-Type: application/javascript
  • css文件 Content-Type: text/css
  • Content-Encoding: gzip
成功页面响应

502

如果访问网站出现 502的情况,检查一下 dist包中 html文件是不是 .gz格式。如果是这种情况,就需要在 Nginx中增加 html处理。

location ~ \.(js|mjs|json|css|html)$ {
  gzip_static on;
}

总结

最后来看一下 Nginx的配置。考虑到浏览器兼容性,有些浏览器不支持 gzip压缩,大家在 build阶段,不要删除源文件,尽可能保证 .gz文件及其源文件同时存在。

server {
  listen 80 default_server;
  listen [::]:80 default_server;
  root   /usr/share/nginx/html;

  gzip_static on;
  gzip on;
  gzip_vary on;
  gzip_min_length 1k;
  gzip_proxied expired no-cache no-store private auth;
  gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml application/javascript;
  gzip_disable "MSIE [1-6]\.";

  location ~ \.(js|mjs|json|css|html)$ {
    gzip_static on;
  }

  location / {
    try_files $uri $uri/ /index.html;
    index  index.html index.htm;
  }
}

希望能帮助大家,3Q!