如何通过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(); }); }); }, }, }, }, }; });
关键修改点说明
- 暂停原始响应流:调用
proxyRes.pause()阻止http-proxy自动把原始数据转发给客户端,确保只有处理后的内容会被返回。 - 更新响应头:
- 删除
content-encoding:已解压内容,客户端无需再执行解压操作。 - 删除原
content-length:内容修改后长度变化,需重新计算并设置新值。
- 删除
- 统一处理逻辑:抽离
processBody函数,同时兼容压缩和未压缩的响应场景。 - 错误处理:增加解压失败和响应流错误的处理逻辑,避免服务崩溃,出错时可返回原始内容作为降级方案。
内容的提问来源于stack exchange,提问作者timtheone
相关产品推荐
相关产品推荐

