我们都知道SSE是一种特殊的 content-type,用于实现服务器持续的通过HTTP输出数据,目前最常见的运用点就是在AI聊天中实现"打字机"般的输出效果。
        目前的项目大部分都是前后端分离的,其中前端的 Vue 脚手架工程我们都用的很多,而且会经常使用 webpack-dev-server 来避免 跨域问题。然而,webpack-dev-server 却给 SSE 埋了一个巨大的地雷,下面我会解释这个“雷”是什么,以及如何解决。

下面我们先来看看问题是什么:

        我的提示词是“生成一个1000字左右的文章”,可以看到在发出请求30秒后,浏览器才接受到服务器的数据,而且通过观察响应我发现所有的chunk在某一个时间点被同时传递到了浏览器,在这显然不是我们想要的,这也违背了流式传输的初衷,然而奇怪的是,当我们使用API调试工具,比如 ApiFox 时:


        可以看到仅仅6秒过后就开始了传输,考虑到网络和大语言模型计算的时间,6秒绝对是个合理的时间,那么到底是什么导致了浏览器和API调用工具的响应时间相差几乎5倍?

        为了方便大家理解问题的根源,我在这里先引出一个技术也就是罪魁祸首 content-ecoding,那么,什么是 content-ecoding 呢?
        content-ecoding 是一种HTTP协议机制,它指出来自服务器或客户端(如浏览器)的“消息体”(body)在传输过程中被压缩或编码的方式。而其中常用的有 gzip、br、deflate,而identity表示不压缩。
        然而压缩有一个行为,为了提高压缩效率它会缓存数据到一定大小后才会进行压缩和传输,或者连接断开,也就是说浏览器30秒才收到响应是因为服务器断开了连接导致数据被迫压缩然后传输,这么看来30秒的时间就显得合理了。
        你可能会想,那就给服务器加上 content-ecoding : identity 不就行了,每错,但是不要忘记了这篇文章的标题。



        问题又来了,是谁给我们的响应加上了content-ecoding?我们可以通过响应头看,这是浏览器的响应体:

        明显看到这里使用了br作为压缩算法,也就是我们的SSE被压缩缓存了,而 ApiFox 的响应头是这样的:

可以看到在这里就没有了content-ecoding,也就是 直接到服务器没有content-encoding,而浏览器到服务器就有这个了,是浏览器加的吗?不,浏览器可做不到这个功能,那么所有的线索指向了一个,代理服务器webpack-dev-server,我们经常会去这么配置webpack-dev-server:

module.exports = {
  devServer: {
    port: 10000,
    proxy: {
      '/api': {
        target: 'http://localhost:20000',
        changeOrigin: true,
        pathRewrite: { 
          '/api': '' 
        }
      }
    }
  }
};

        这里有一个默认的配置叫做 compress: true,他会默认开启压缩,也就是说服务器先发送给webpack-dev-server后经过压缩后在送到浏览器,这就是为什么我说在服务器设置content-encoding : identity 是无效的原因,那么既然如此,我们只需要显式的把 compress 设置为 fasle:
        

module.exports = {
  devServer: {
    port: 10000,
    compress: false,
    proxy: {
      '/api': {
        target: 'http://localhost:20000',
        changeOrigin: true,
        pathRewrite: { 
          '/api': '' 
        }
      }
    }
  }
};

重启 webpack-dev-server,我们在看看响应头如何:

很好,我们成功消灭了content-encoding,那么这真的有用吗?来看效果

服务器在2.17秒就开始返回数据,效果之显著

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐