You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS移动端JS资源未Gzip压缩:请求头来源与修复方案咨询

答:

嘿,这个问题我之前也碰到过类似的,来给你梳理清楚:

首先明确:Accept-Encoding 请求头是谁加的?

完全是浏览器自动添加的,NextJS 和 Webpack 都不会干预浏览器发送这个请求头。浏览器会根据自身设置、网络环境等,决定是否带上这个头来告诉服务器:“我支持压缩格式,麻烦给我发压缩后的资源”。桌面端和移动端的差异,本质是不同环境下浏览器的行为不同。

为什么移动端没带这个头?

大概率是这几个原因:

  • 移动端浏览器开启了数据节省模式(比如 Chrome 的 Data Saver、Safari 的 Low Data Mode),这类模式会主动移除或修改 Accept-Encoding 头,避免压缩带来的额外CPU开销(毕竟移动端性能相对有限);
  • 部分小众移动端浏览器的默认设置就是不发送这个头;
  • 如果是用模拟器测试,可能模拟器的网络配置模拟了低带宽/省流量场景,导致浏览器屏蔽了该头。

怎么修复这个问题?

既然没法给 <script> 标签加请求头,我们可以从服务器端强制压缩资源,或者排查浏览器设置:

方案1:让 NextJS 强制返回压缩后的 JS 资源

即使请求头不带 Accept-Encoding,也主动返回 Gzip 压缩后的内容。可以通过两种方式实现:

方式A:用 Webpack 预压缩资源

提前生成 Gzip 格式的 JS 文件,让 NextJS 优先返回这些预压缩文件:

  1. 安装压缩插件:
npm install compression-webpack-plugin --save-dev
  1. 修改 next.config.js:
const CompressionPlugin = require('compression-webpack-plugin');

/** @type {import('next').NextConfig} */
const nextConfig = {
  compress: true, // 确保开启服务器压缩
  webpack: (config) => {
    config.plugins.push(
      new CompressionPlugin({
        algorithm: 'gzip',
        test: /\.(js|css|html|svg)$/, // 匹配需要压缩的文件类型
        threshold: 8192, // 只有大于8KB的文件才压缩
        minRatio: 0.8, // 压缩率低于0.8的才保留压缩文件
      })
    );
    return config;
  },
};

module.exports = nextConfig;

构建生产版本后,NextJS 的服务器会自动检测并返回预生成的 .gz 文件,无需依赖请求头(不过部分场景下还是需要浏览器支持解压缩,但现在主流移动端浏览器都支持)。

方式B:用 NextJS 中间件强制压缩响应

创建 middleware.ts(或 .js),拦截 JS 请求并主动压缩:

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import zlib from 'zlib';
import { promisify } from 'util';

const gzip = promisify(zlib.gzip);

export async function middleware(request: NextRequest) {
  // 只处理静态JS chunk
  if (request.nextUrl.pathname.match(/\/_next\/static\/.*\.js$/)) {
    const originalResponse = await fetch(request.url);
    const body = await originalResponse.text();
    const compressedBody = await gzip(body);

    return new NextResponse(compressedBody, {
      status: originalResponse.status,
      headers: {
        ...originalResponse.headers,
        'Content-Encoding': 'gzip',
        'Content-Length': compressedBody.length.toString(),
        'Vary': 'Accept-Encoding', // 保留Vary头,避免缓存问题
      },
    });
  }

  return NextResponse.next();
}

这个中间件会自动处理所有 NextJS 生成的静态 JS 资源,不管请求头有没有 Accept-Encoding,都返回 Gzip 压缩后的内容。

方案2:排查移动端浏览器设置

如果是测试时的临时问题,可以检查移动端浏览器是否开启了省流量模式,关闭后浏览器应该会自动带上 Accept-Encoding 头,服务器也就会返回压缩后的资源了。

方案3:确认 Vary 头配置

确保 NextJS 返回的响应头里包含 Vary: Accept-Encoding,这样如果有缓存层(比如 CDN),会根据请求头的不同存储不同的压缩/未压缩版本,避免移动端拿到缓存的未压缩资源。


内容的提问来源于stack exchange,提问作者darKnight

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:30:04