You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AJAX强制下载PDF文件损坏:如何修复Blob创建环节的编码问题?

问题

通过服务器端cURL调用API获取包含base64编码PDF的XML文件,提取PDF后用PHP临时保存并输出,前端通过AJAX接收并创建Blob下载,但生成的PDF文件损坏无法正常打开。

后端PHP代码

<?php

$pdfContents = $content["DocumentHeader"]["DocumentPdf"]; // base64 string PDF
$endDocument = base64_decode($pdfContents);
$realName = 'some_random_string.pdf';
$filename = 'adjusted_name.pdf';
file_put_contents($realName,$endDocument);

header('Content-Description: File Transfer');
header('Content-type: application/octetstream');
header('Content-Disposition: attachment; filename='.$filename);
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Transfer-Encoding: binary');
readfile($realName);

unlink($realName);

die();
?>

前端AJAX代码

$.ajax({
    url: 'get-file.php',
    type: 'GET',
    data: {},
    success:function(data,status,xhr) {
        var blob = new Blob([data], { type:'application/pdf' });
        var downloadUrl = URL.createObjectURL(blob);

        window.location.href = downloadUrl;
    }
});

已尝试的调整均无效:

  • 修改后端Content-Type为application/pdf
  • 移除Content-Transfer-Encoding头
  • 使用TextEncoder/Decoder处理数据
  • 将data转换为Uint8Array创建Blob

约束条件:

  • 不直接提供PDF链接:需隐藏真实文件名、避免服务器长期留存文件,支持数百用户同时使用
  • 不设置AJAX的responseType为blob:响应可能是包含错误信息的JSON
  • 使用AJAX:避免浏览器拦截新标签,保持用户在当前页面

解决方案

问题核心是AJAX默认以字符串格式接收二进制数据时会出现编码错乱,导致Blob损坏。以下是针对性的修复方案:

1. 后端优化(可选但推荐)

去掉不必要的临时文件写入,直接输出解码后的二进制内容,同时修正响应头确保数据完整性:

<?php
$pdfContents = $content["DocumentHeader"]["DocumentPdf"];
$endDocument = base64_decode($pdfContents);
$filename = 'adjusted_name.pdf';

// 清理可能存在的多余输出,避免混入二进制数据
ob_clean();
flush();

header('Content-Description: File Transfer');
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
// 增加内容长度头,帮助前端准确处理数据
header('Content-Length: ' . strlen($endDocument));

echo $endDocument;
die();
?>

2. 前端正确处理二进制数据

使用responseType: 'arraybuffer'接收原始二进制数据,再通过响应头区分PDF和错误JSON:

$.ajax({
    url: 'get-file.php',
    type: 'GET',
    data: {},
    responseType: 'arraybuffer', // 以ArrayBuffer格式接收,完整保留原始字节
    success:function(data, status, xhr) {
        var contentType = xhr.getResponseHeader('Content-Type');
        // 区分PDF和错误JSON响应
        if (contentType === 'application/pdf') {
            // 直接用ArrayBuffer创建Blob
            var blob = new Blob([data], { type: 'application/pdf' });
            var downloadUrl = URL.createObjectURL(blob);
            
            // 创建a标签触发下载,比直接跳转更稳定
            var a = document.createElement('a');
            a.href = downloadUrl;
            // 可从响应头提取文件名:xhr.getResponseHeader('Content-Disposition').split('filename=')[1]
            a.download = 'adjusted_name.pdf'; 
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(downloadUrl); // 释放浏览器资源
        } else {
            // 将ArrayBuffer转为字符串解析错误JSON
            var decoder = new TextDecoder('utf-8');
            var errorJson = decoder.decode(data);
            var errorObj = JSON.parse(errorJson);
            // 这里添加错误提示逻辑
            console.error('请求出错:', errorObj);
        }
    },
    error: function() {
        console.error('请求失败');
    }
});

关键说明

  • responseType: 'arraybuffer'是核心:它会跳过字符串编码转换,完整保留PDF的原始二进制字节,避免编码丢失
  • 通过Content-Type头区分响应类型,既满足二进制PDF的处理需求,又能兼容错误JSON的解析
  • 使用a标签触发下载比直接window.location.href更稳定,还能指定自定义文件名

内容的提问来源于stack exchange,提问作者FiddlingAway

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 07:05:33