PHP实现的内嵌PDF展示功能在Chrome、Edge中下载报错问题
问题根因
2023年5月推送的Chromium 113版本(同步覆盖Edge 113+)调整了inline模式PDF资源的下载校验逻辑:当从内嵌预览界面触发下载操作时,浏览器会重新校验资源响应头的完整性,若缺失Content-Length字段,会判定资源不可用,直接抛出网络错误,哪怕缓存中已存在完整的PDF文件内容也不会调用。
Firefox未调整相关逻辑,所以功能正常。
现象解释
- 文件名识别异常:Chromium 113+之后,下载inline模式的PDF时,不会优先读取
Content-Disposition头中的filename参数,默认取当前页面URL的最后一段作为文件名,只有响应头完整符合要求时才会读取自定义文件名。 - 无新请求产生:预览PDF时资源已完整加载到浏览器缓存,打印和下载操作都会优先调用缓存内容,不会发起新请求。
- 打印正常但下载失败:打印逻辑直接调用预览界面已加载到内存的渲染后数据,不需要做资源完整性校验;下载逻辑需要走文件保存的安全校验流程,会校验响应头的必填字段是否完整,校验不通过就会报错。
修复方案
在现有响应头中添加Content-Length头即可解决问题,修改后的代码如下:
header('Content-Type: application/pdf'); header('Content-Disposition: inline; filename="' . $deliveryPdf->getFilename() . '"'); header('Content-Transfer-Encoding: binary'); header('Accept-Ranges: bytes'); // 新增Content-Length头,指定PDF文件的实际大小 header('Content-Length: ' . strlen($deliveryPdf->getData())); echo $deliveryPdf->getData();
额外注意事项
- 若服务器对
application/pdf类型的响应开启了gzip、Brotli等压缩,需要关闭该类资源的压缩规则,否则实际传输的文件大小和Content-Length指定的大小不一致,仍会触发校验失败。 - 不要省略输出的PDF内容的长度计算,哪怕PDF内容存在动态生成的场景,也要确保
Content-Length的值和实际输出的二进制内容长度完全一致。
内容的提问来源于stack exchange,提问作者Marcel Kirsch
相关产品推荐
相关产品推荐

