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

如何通过Vite代理配置修改HTML响应内容

Vite代理修改压缩响应不生效的解决方法

问题描述

我配置了Vite的代理,想要读取远程返回的压缩响应、解压后修改内容再返回给客户端,但修改后的内容并未生效,服务器依然返回原始的HTML。测试直接在end事件里用res.end()返回固定HTML是有效的,但不符合我的实际需求。推测是代理响应采用流式传输,开发服务器没等我的处理完成就返回了原始文档。

原始Vite配置代码

import { defineConfig } from "vite";

const zlib = require("zlib");

export default defineConfig(() => {
  return {
    server: {
      proxy: {
        "/start": {
          target: "https://someremoteurl.com",
          secure: false,
          changeOrigin: true,
          configure: (proxy) => {
            proxy.on("proxyRes", (proxyRes, req, res) => {
              const chunks = [];
              
              proxyRes.on("data", (chunk) => chunks.push(chunk));
              proxyRes.on("end", () => {
                const buffer = Buffer.concat(chunks);
                const encoding = proxyRes.headers["content-encoding"];
                if (encoding === "gzip" || encoding === "deflate") {
                  zlib.unzip(buffer, (err, buffer) => {
                    if (!err) {
                      let remoteBody = buffer.toString();
                      const modifiedBody = remoteBody.replace() // 此处已完成自定义的字符串修改
                      res.write(modifiedBody);
                      res.end();
                    } else {
                      console.error(err);
                    }
                  });
                }
              });
            });
          },
        },
      },
    },
  };
});

测试有效但不符合需求的代码

proxyRes.on("end", () => {
  res.end('<h1>Some Test HTML</h1>')
});

解决方案

核心问题是默认情况下http-proxy会自动转发原始响应流到客户端,所以需要暂停原始流并拦截自动转发,同时处理响应头的更新:

修改后的完整配置代码:

import { defineConfig } from "vite";
const zlib = require("zlib");

export default defineConfig(() => {
  return {
    server: {
      proxy: {
        "/start": {
          target: "https://someremoteurl.com",
          secure: false,
          changeOrigin: true,
          configure: (proxy) => {
            proxy.on("proxyRes", (proxyRes, req, res) => {
              // 暂停原始响应流,阻止自动转发给客户端
              proxyRes.pause();

              // 删除content-encoding头,因为我们会解压后返回明文
              delete proxyRes.headers["content-encoding"];
              // 删除原content-length,内容修改后长度会变化
              delete proxyRes.headers["content-length"];

              const chunks = [];
              
              proxyRes.on("data", (chunk) => chunks.push(chunk));
              proxyRes.on("end", () => {
                const buffer = Buffer.concat(chunks);
                const encoding = proxyRes.headers["content-encoding"];

                const processBody = (dataBuffer) => {
                  let remoteBody = dataBuffer.toString();
                  // 执行自定义修改逻辑,示例为替换内容
                  const modifiedBody = remoteBody.replace(/原始内容/g, "修改后的内容");
                  // 设置新的content-length
                  res.setHeader("content-length", Buffer.byteLength(modifiedBody));
                  // 返回修改后的内容
                  res.end(modifiedBody);
                };

                if (encoding === "gzip" || encoding === "deflate") {
                  zlib.unzip(buffer, (err, decompressedBuffer) => {
                    if (!err) {
                      processBody(decompressedBuffer);
                    } else {
                      console.error("解压失败:", err);
                      // 解压失败时返回原始内容
                      res.end(buffer);
                    }
                  });
                } else {
                  // 响应未压缩,直接处理
                  processBody(buffer);
                }

                // 恢复原始流(可选,已处理完所有数据)
                proxyRes.resume();
              });

              // 监听错误事件,避免异常崩溃
              proxyRes.on("error", (err) => {
                console.error("响应流错误:", err);
                res.end();
              });
            });
          },
        },
      },
    },
  };
});

关键修改点说明

  1. 暂停原始响应流:调用proxyRes.pause()阻止http-proxy自动把原始数据转发给客户端,确保只有处理后的内容会被返回。
  2. 更新响应头:
    • 删除content-encoding:已解压内容,客户端无需再执行解压操作。
    • 删除原content-length:内容修改后长度变化,需重新计算并设置新值。
  3. 统一处理逻辑:抽离processBody函数,同时兼容压缩和未压缩的响应场景。
  4. 错误处理:增加解压失败和响应流错误的处理逻辑,避免服务崩溃,出错时可返回原始内容作为降级方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 21:35:16