如何让Service Worker返回带Transfer-Encoding: chunked头的响应?
问题分析与修正方案
一、请求头设置的错误点
错误设置CORS相关头:
Access-Control-Allow-Origin和Access-Control-Allow-Credentials是服务器端用于跨域校验的响应头,手动在Service Worker中设置容易触发浏览器的CORS校验异常。如果字体请求是同域的,直接移除这两个头;如果是跨域场景,确保请求本身是合法的跨域类型后再考虑是否保留。Content-Encoding头不匹配:如果你的uint8Array是未压缩的原始TTF文件,却设置了Content-Encoding: gzip,浏览器会尝试用gzip解压内容,直接导致字体解析失败。若文件确实是gzip压缩的,要确认file是压缩后的二进制数据;否则直接删除这个头。多余的传输层头:
Transfer-Encoding: chunked、Date、Connection、Keep-Alive这些头由浏览器或底层传输层自动处理,手动设置不仅无效,还可能和浏览器默认行为冲突,全部移除即可。Cache-Control设置不合理:max-age=0会强制浏览器每次重新请求,若需要缓存字体,建议改成public, max-age=31536000(一年)这类合理值,按需调整。
修正后的请求头示例:
options.headers = new Headers({ 'Accept-Ranges': 'bytes', 'Cache-Control': 'public, max-age=31536000', 'Last-Modified': 'Thu, 23 May 2024 00:29:23 GMT', 'Content-Type': 'font/ttf', 'Vary': 'Accept-Encoding' });
二、Response返回逻辑的问题
- 无需包装ReadableStream:已经拿到
Uint8Array格式的文件,直接用它创建Response即可,额外包装Stream属于多余操作,还可能引发流处理异常。简化后的代码:
event.respondWith((async () => { const file = await readFile(path); if (destination === 'font') { return new Response(file, options); } // 补充非字体请求的默认处理,避免请求失败 return fetch(event.request); })());
- 缺少默认请求处理:原代码中如果
destination不是font,没有返回任何内容,会导致非字体请求直接失败,必须补充默认的请求转发逻辑。
三、排查步骤
- 验证文件读取结果:在
const file = await readFile(path);后添加console.log(file),确认返回的是正确的Uint8Array,且长度匹配字体文件的实际大小。 - 核对
destination值:确认destination是从event.request.destination获取的,且拼写为小写的font。 - 查看浏览器调试信息:
- 控制台检查是否有字体解析错误、CORS错误或Service Worker运行报错;
- 网络面板查看字体请求的响应状态码、响应头、响应内容,若内容是乱码,大概率是
Content-Encoding头设置错误导致的。
内容的提问来源于stack exchange,提问作者Sergey
相关产品推荐
相关产品推荐

