Skip to content

在 Nginx 中配置和验证 Brotli 压缩

Brotli 是一种新的压缩算法,提供了比传统 Gzip 更高的压缩率,能有效减小网站资源的体积,从而加速页面加载时间。在 Nginx 中启用 Brotli 压缩,可以显著提高网站性能。本文档提供了如何在 Nginx 中配置 Brotli 压缩以及如何验证 Nginx 是否正确安装了 Brotli 模块的指南。

1. 添加 Brotli 模块到 Nginx

由于 Nginx 默认不包含 Brotli 模块,您需要通过编译 Nginx 来添加 Brotli 支持或使用已经包含 Brotli 模块的第三方 Nginx 版本。

使用 Docker 构建包含 Brotli 的 Nginx

如果您使用 Docker 来部署 Nginx,可以通过创建自定义 Dockerfile 来构建一个包含 Brotli 模块的 Nginx 镜像。

当然最简单是使用社区构建好的 Docker 镜像 michaelknightdriver/docker-nginx-brotli(推荐)。

创建 Dockerfile

Dockerfile
# FROM nginx:1.21.6
# 基于 docker-nginx-brotli 镜像
FROM michaelknightdriver/docker-nginx-brotli

# 删除默认配置文件
RUN rm /etc/nginx/conf.d/default.conf

# 复制自定义的Nginx配置文件
COPY nginx.conf /etc/nginx/conf.d/default.conf

创建 nginx.conf

nginx
# upstream 段定义了一组服务器的名称,NGINX 可以将请求代理到该组服务器
upstream loadfrontend {
    # 用于处理 / 路径请求的后端服务器
    server money_backend_frontend:80;
}
upstream loadbackend {
    # 用于处理 /api/ 路径请求的后端服务器
    server money_backend_server:3000;
}

# HTTP服务器配置,用于重定向到HTTPS
server {
    listen 3308; # HTTP监听端口
    server_name docs.ffffee.com; #需要将yourdomain.com替换成证书绑定的域名。
    rewrite ^(.*) https://$server_name:8443$1 permanent; #将所有HTTP请求通过rewrite指令重定向到HTTPS。
}

# server 段定义了对外提供服务的配置
server {
    listen 8443 ssl http2; # HTTPS监听端口
    server_name docs.ffffee.com; # 你的域名

    # SSL证书和密钥位置
    ssl_certificate cert/docs.ffffee.com.pem; # 证书文件路径
    ssl_certificate_key cert/docs.ffffee.com.key; # 私钥文件路径


    # 增强安全性的SSL配置
    # 设置SSL会话的超时时间。5m表示会话超时时间为5分钟。这是一个平衡性能和安全性的设置,较短的超时时间可以减少潜在的会话劫持风险。
    ssl_session_timeout 5m;

    #  定义服务器支持的加密套件。这个列表应该排除已知弱加密和不安全的加密套件。ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4是一个推荐的设置,
    # 它优先使用强加密套件,同时排除了弱加密和易受攻击的加密套件。
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;

    # 指定服务器支持的TLS协议版本。推荐启用TLSv1.2和TLSv1.3,因为它们提供了较强的安全性。
    # TLSv1.1通常不推荐使用,除非是为了向后兼容性考虑,但请注意,随着时间的推移,更多的客户端和服务会弃用TLS 1.1。
    ssl_protocols TLSv1.2 TLSv1.3; # 如果需要向后兼容,则考虑包含TLSv1.1

    # ssl_prefer_server_ciphers: 设置为on时,服务器将按照ssl_ciphers指令中定义的顺序,优先使用服务器端的加密套件选择,而不是客户端提议的顺序。这有助于确保使用最强的加密套件。
    ssl_prefer_server_ciphers on;

    client_max_body_size 10m; # 客户端最大上传大小限制 10MB
    # # 监听端口 3308
    # listen 3308;
    # # 服务器名称,需要替换成证书绑定的域名
    # server_name localhost;

    # location 段定义了处理不同 URL 路径的配置
    location / {
        # Brotli设置
        brotli on;
        brotli_static on;
        brotli_comp_level 6;
        brotli_types text/plain text/css application/javascript application/json image/svg+xml application/xml+rss;

        # 启用gzip_static,优先发送预压缩的.gz文件(如果存在)
        gzip_static on;
        # 为了向后兼容不支持gzip的客户端,保留gzip on
        gzip on;
        # 配置gzip压缩的最小文件大小,避免压缩太小的文件
        gzip_min_length 256;
        # 配置压缩的类型,根据需要进行添加
        gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css application/xml image/svg+xml;

        # 代理请求到 loadfrontend 组的后端服务器
        proxy_pass http://loadfrontend;

        # 设置请求头信息,这些头信息会被转发给后端服务器
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # 设置 cookie 属性,增强安全性
        proxy_cookie_path / "/; httponly; secure; SameSite=Strict";
    }
    location ^~/api/ {
        # 代理请求到 loadbackend 组的后端服务器
        proxy_pass http://loadbackend;

        # 设置请求头信息,这些头信息会被转发给后端服务器
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # 设置 cookie 属性,增强安全性
        proxy_cookie_path / "/; httponly; secure; SameSite=Strict";
    }
}

构建和运行容器

bash
docker build -t nginx_with_brotli .
docker run -p 80:80 -p 443:443 nginx_with_brotli

2. 配置 Nginx 以使用 Brotli 压缩

在 Nginx 配置文件中启用 Brotli 压缩。通常,这需要在nginx.conf文件的http块中添加以下配置:

nginx
http {
    brotli on;
    brotli_comp_level 6;
    brotli_static on; # 仅对预先压缩的文件生效
    brotli_types text/plain text/css application/javascript application/json image/svg+xml application/xml+rss;
}

3. 验证 Brotli 模块

方法 1:使用nginx -V

在命令行中执行nginx -V,并在输出中查找包含“brotli”的文本,确认 Brotli 模块已经被编译到 Nginx 中。

bash
nginx -V 2>&1 | grep brotli

如果这条命令返回了与 Brotli 相关的配置信息,表示 Brotli 模块已经安装。

方法 2:通过配置文件测试

nginx.conf添加 Brotli 相关配置,重启 Nginx,并检查错误日志以确认 Brotli 配置没有引发错误。

注意事项

  • 确保您的 Nginx 版本与您尝试使用的 Brotli 模块版本兼容。
  • 测试配置更改前后的网站性能,确保 Brotli 压缩带来的是正面效果。
  • 验证客户端(如浏览器)是否支持 Brotli 压缩,因为不是所有的浏览器都支持此特性。

通过上述步骤,您可以在 Nginx 中成功配置 Brotli 压缩,并验证其正确安装和工作状态。这将有助于提升您网站的加载速度和用户体验。

vite.config.js 配置

js
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { visualizer } from "rollup-plugin-visualizer"; // 分析包
import viteCompression from "vite-plugin-compression"; // 生成gzip/brotli压缩的.gz和.br文件插件

// https://vitejs.dev/config/
// eslint-disable-next-line no-unused-vars
export default defineConfig(({ command, mode }) => ({
  plugins: [
    vue(),
    // 使用 compression 插件
    viteCompression({
      verbose: true, // 是否在控制台输出压缩结果
      disable: false, // 默认 false, 设置为 true 来禁用压缩
      threshold: 10240, // 只处理大于此大小的资源(单位:字节)。默认值为 0。
      algorithm: "gzip", // 使用 gzip 压缩
      ext: ".gz", // 输出文件的扩展名
    }),
    viteCompression({
      verbose: true, // 是否在控制台输出压缩结果
      disable: false, // 默认 false, 设置为 true 来禁用压缩
      threshold: 10240, // 只处理大于此大小的资源(单位:字节)。默认值为 0。
      algorithm: "brotliCompress", // 使用 brotli 压缩
      ext: ".br", // 输出文件的扩展名
    }),
    visualizer({
      open: true,
      gzipSize: true,
      brotliSize: true,
      emitFile: true,
      filename: "stats.html",
    }),
  ],
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
  },
  build: {
    rollupOptions: {
      output: {
        manualChunks(id) {
          // 文件路径 id
          console.log(id);

          const chunkArray = [
            "dayjs",
            "@element-plus",
            "vue",
            "vue-router",
            "echarts",
          ];

          if (
            chunkArray.find((chunk) => id.includes(`node_modules/${chunk}/`))
          ) {
            return id
              .toString()
              .split("node_modules/")[1]
              .split("/")[0]
              .toString();
          }
        },
        chunkFileNames: (chunkInfo) => {
          const facadeModuleId = chunkInfo.facadeModuleId
            ? chunkInfo.facadeModuleId.split("/")
            : [];
          const fileName =
            facadeModuleId[facadeModuleId.length - 2] || "[name]";
          return `js/${fileName}/[name].[hash].js`;
        },
      },
    },
  },
  server: {
    proxy: {
      // 当您的前端代码请求 `/api` 路径时,它将被代理到 `http://backend.server.com`
      "/api": "http://localhost:3000",
      // '/api': 'http://ffffee.com:3308'
    },
  },
}));