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

React Fetch调用Java REST API下载PDF无法在Adobe打开的问题

问题描述

我在Postman中测试过该API,PDF可正常渲染,确认API功能正常。但通过React代码使用Fetch下载PDF时,Adobe提示错误:“Adobe Acrobat无法打开该文件,因为它不是支持的文件类型或文件已损坏”。下载的文件大小恰好为1kb,说明未正确从API获取Blob。查阅网上示例但未发现问题,相关代码如下:

React代码

const downloadFile = async uploadId => {
    const response = await callFetch("/uploads/download/" + uploadId + "?officerId=" + officerId, "GET", "");
    if (response.status === 401 || response.status === 403) {
        alert("Error " + response.status);
        sessionStorage.clear();
        return;
    }

    const file = response.blob();
    const url = URL.createObjectURL(
        new Blob([file], {type:"application/pdf"})
    );

    const filename = response.headers.get("Content-Disposition").split("filename=")[1];

    const link = document.createElement('a');
    link.href = url;
    link.setAttribute(
        'download',
        filename,
    );

    document.body.appendChild(link);
    link.click();
    link.parentNode.removeChild(link);
    URL.revokeObjectURL(url);
};

const callFetch = (endpoint, method, jsonStr) => {
    let myHeaders = new Headers();
    myHeaders.append("Content-Type", "application/json");
    myHeaders.append("Accept","application/json");
    return callFetchApi(endpoint, method, jsonStr, myHeaders);
};

const callFetchApi = (endpoint, method, data, myHeaders) => {
    const serverName = "http://localhost:8080/AuxPolice/api";
    myHeaders.append("Access-Control-Allow-Credentials", 'true');
    myHeaders.append("Access-Control-Allow-Origin", '*');

    const jwt = sessionStorage.getItem("jwt");
    let headerJwt = "Bearer " + jwt;
    if (jwt != null) {
        myHeaders.append("Authorization", headerJwt);
    }

    let myInit = {
        method: method,
        headers: myHeaders
    };

    let url = serverName + endpoint;

    if (data) {
        myInit.body = data;
    }

    return fetch(url, myInit);
};

Java后端代码

@GetMapping(value = "/download" + "/{id}")
public ResponseEntity<Resource> downloadGet(@PathVariable Long id, @RequestParam Long officerId) throws SQLException
{
    Officer loggedInOfficer = this.auxPoliceService.getOfficer(officerId);
    
    Upload paramRec = new Upload();
    paramRec.setUploadId(id);

    Upload download = auxPoliceService.getUploads(loggedInOfficer.getOfficerId(), paramRec).get(0);
    
    Blob blob = download.getBlob();
    byte [] bytes = blob.getBytes(1, (int)blob.length());
    blob.free();

    InputStreamResource resource = new InputStreamResource(new ByteArrayInputStream(bytes));
    
    String filename = download.getFilename(); 
    String contentType = "application/pdf";

    HttpHeaders headers = new HttpHeaders();
    headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION);
    headers.add("Content-Disposition", "inline; filename=" + filename);
    
    return ResponseEntity.ok()
            .headers(headers)
            .contentLength(bytes.length)
            .contentType(MediaType.parseMediaType(contentType))
            .body(resource);
}
排查思路
  • 异步方法未等待:response.blob()是异步Promise方法,必须加await才能拿到实际的Blob对象。当前代码直接把Promise对象传入Blob构造函数,生成的是包含Promise的无效Blob,这是文件损坏的核心原因。修改为:

    const file = await response.blob();
    
  • 请求头Accept设置错误:callFetch中设置了Accept: application/json,但API返回的是PDF二进制数据,这个头会让Fetch尝试将响应解析为JSON,导致二进制数据损坏。将Accept改为application/pdf,或者直接删除该头。

  • 冗余的Blob构造:response.blob()已经返回了正确的PDF Blob,无需再用new Blob([file], {type:"application/pdf"})包裹,直接使用file即可:

    const url = URL.createObjectURL(file);
    
  • 错误的CORS请求头:callFetchApi中手动添加的Access-Control-Allow-Credentials和Access-Control-Allow-Origin是服务器响应头,客户端请求时不需要设置,直接删除这两行代码,避免干扰请求。

  • 文件名解析鲁棒性不足:Content-Disposition的文件名可能带引号(如filename="xxx.pdf"),直接用split会拿到带引号的字符串。建议用正则提取:

    const disposition = response.headers.get("Content-Disposition");
    const filename = disposition?.match(/filename="?([^"]+)"?/)?.[1] || "download.pdf";
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 20:15:50