掘金文章归档 · 第 68 篇 工程化 · Vite

解决 vite 环境下调用获取二进制文件流 部分文件报错 (failed) net::ERR_INVALID_HTTP_RESPONSE

现象 → 代理配置修复 → 原理剖析 → Content-Length 机制详解

原文作者:随意_(掘金) | juejin.cn/post/7551023096965152795 | 发布于 2025-09-18 | 阅读 983 · 约 5 分钟

0背景

对于同一个文件,通过接口来获取二进制文件流的时候,线上部署环境是 ok 的,可以正常下载,但是本地的 vite proxy 代理对于同一个文件展示不同的效果,会直接拒绝访问,报错信息为:

(failed)

net::ERR_INVALID_HTTP_RESPONSE

1解决办法:代理中增加二进制处理配置 configure

configure: (proxy, options) => {
  proxy.on('proxyRes', (proxyRes, req, res) => {
    // 检测二进制流类型的响应
    if (proxyRes.headers['content-type'] &&
        (proxyRes.headers['content-type'].includes('application/octet-stream') ||
         proxyRes.headers['content-type'].includes('application/pdf') ||
         proxyRes.headers['content-type'].includes('image/'))) {
      // 删除 Content-Length 头
      delete proxyRes.headers['content-length'];
    }
  });
}

在 vite.config 的 proxy 配置中加入 configure 钩子,监听 proxyRes 事件,对二进制类型响应删除 content-length 头即可。

2原理:Vite 代理默认行为与二进制流的冲突

Vite 的代理功能基于 http-proxy 库实现,其默认配置会对响应做一些"优化处理",比如:

这些处理对普通 JSON / 文本响应没问题,但对二进制流(如文件、图片、PDF 等)会造成严重问题:

3配置生效的关键原因

上面这段配置的作用是:

4额外说明

对于二进制流,正确的传输方式通常是:

Vite 的默认代理配置没有针对二进制流做特殊处理,而我们的自定义配置正是修复了这个问题,让二进制数据能够原封不动地从后端传输到前端,从而与线上环境保持一致的行为。

5有些文件可以成功,有些不可以的原因:文件大小触发不同传输模式

6Content-Length 介绍

Content-Length 的工作流程涉及客户端与服务器之间的"长度协商",核心是"客户端告知服务器自己要发多少数据"和"服务器告知客户端会收到多少数据",两者是独立的。

1. 基本流程:客户端与服务器的双向长度告知

(1)客户端 → 服务器(请求阶段)

当客户端向服务器发送数据时(如 POST 表单、上传文件),可能会在请求头中携带 Content-Length,用于告知服务器:"我接下来要发的数据总共有 X 字节,请准备接收这么多"。例如:

POST /upload HTTP/1.1
Host: example.com
Content-Length: 1024  # 客户端告知:本次请求体有1024字节
Content-Type: application/octet-stream

[1024字节的二进制数据]

(2)服务器 → 客户端(响应阶段)

当服务器向客户端返回数据时(如返回文件、接口响应),会在响应头中携带 Content-Length,用于告知客户端:"我接下来要返回的数据总共有 Y 字节,请准备接收这么多"。例如:

HTTP/1.1 200 OK
Content-Length: 2048  # 服务器告知:本次响应体有2048字节
Content-Type: application/pdf

[2048字节的PDF二进制数据]

此时客户端(浏览器)会根据这个值来判断是否已接收完整数据(如果实际收到的字节数 ≠ Content-Length,会判定为"响应无效",触发 ERR_INVALID_HTTP_RESPONSE 等错误)。

2. 关键问题:为什么代理会导致 Content-Length 不匹配?

问题出在服务器 → 客户端的响应阶段,且与 Vite 代理(基于 http-proxy)的处理逻辑相关:

3. 总结

📌 Content-Length 的核心作用是"预先告知数据总长度",确保通信双方能校验数据完整性。你的问题中,代理的自动计算破坏了这种完整性校验,因此删除 Content-Length 后,浏览器会通过分块传输自然接收完整数据,反而避免了错误。