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

如何在网页浏览器中展示Fortnox API返回的原始PDF?

问题:如何正确展示Fortnox API返回的PDF文件

我尝试通过Fortnox API获取原始PDF文件(示例内容:%PDF-1.4 %���� 1 0 obj),并在前端点击后展示,但目前无法正常渲染。之前试过用FPDF解析失败,现有PHP获取代码、WordPress AJAX钩子及前端PDF.js渲染代码如下,求解决方法。

当前PHP获取PDF代码

public function showFile($access_token, $file_id)
{
    $curl = curl_init();

    curl_setopt_array($curl, array(
        CURLOPT_URL => "https://api.fortnox.se/3/archive/" . $file_id,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING => "",
        CURLOPT_MAXREDIRS => 10,
        CURLOPT_TIMEOUT => 0,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => "GET",
        CURLOPT_HTTPHEADER => array(
            "Authorization: Bearer " . $access_token
        ),
    ));
    $response = curl_exec($curl);

    curl_close($curl);

    return $response;
}

WordPress AJAX钩子及前端代码

PHP钩子

function getFile()
{
    $fileId = $_POST['fileId'];
    $fortnox = new BDCG_Fortnox();
    $fortnox_token = $fortnox->token();

    $file = $fortnox->showFile($fortnox_token, $fileId);
    
    echo $file;
    
    die();
}

add_action("wp_ajax_get_file", "getFile");
add_action("wp_ajax_nopriv_get_file", "getFile");

前端JS代码

jQuery(document).ready(function () {
  jQuery('.voucher-row').click(function () {
    const fileId = jQuery(this).data('fileid')
    getFile(fileId)
  })
})

function getFile(fileId) {
  jQuery.ajax({
    url: my_ajax_object.ajax_url,
    type: 'POST',
    data: {
      fileId: fileId,
      action: 'get_file',
    },
    success: function (data) {
      displayPdf(data)
    },
    error: function (x, y, z) {
      console.error(x, y, z)
    },
  })
}

function displayPdf(data) {
  // Create a new PDF.js object with the received data
  const pdfData = new Uint8Array(data);
  pdfjsLib.getDocument({ data }).promise.then((pdf) => {
    // Get the first page of the PDF
    pdf.getPage(1).then((page) => {
      // Set the scale of the page
      const scale = 1.5;

      // Get the viewport of the page at the given scale
      const viewport = page.getViewport({ scale: scale });

      // Set the canvas element for rendering the PDF page
      const canvas = document.createElement("canvas");
      const context = canvas.getContext("2d");
      canvas.height = viewport.height;
      canvas.width = viewport.width;
      document.getElementById("pdf-container").appendChild(canvas);

      // Render the PDF page on the canvas
      const renderContext = {
        canvasContext: context,
        viewport: viewport,
      };
      page.render(renderContext);
    });
  });
}

问题原因及解决方法

核心问题

  1. AJAX接收的是字符串而非二进制数据:默认jQuery AJAX会把响应解析为字符串,而PDF是二进制格式,直接转Uint8Array会导致数据损坏。
  2. PHP未设置正确的响应头:返回PDF时没有指定Content-Type: application/pdf,也没有处理二进制输出的编码问题。

解决方案

1. 修改PHP AJAX钩子代码

在输出PDF前设置正确的响应头,并确保输出二进制数据:

function getFile()
{
    $fileId = $_POST['fileId'];
    $fortnox = new BDCG_Fortnox();
    $fortnox_token = $fortnox->token();

    $file = $fortnox->showFile($fortnox_token, $fileId);
    
    // 设置PDF响应头
    header('Content-Type: application/pdf');
    header('Content-Length: ' . strlen($file));
    // 禁用缓存
    header('Cache-Control: no-cache, no-store, must-revalidate');
    header('Pragma: no-cache');
    header('Expires: 0');
    
    echo $file;
    die();
}

2. 修改前端AJAX请求配置

让jQuery接收二进制数据,设置xhrFields和responseType:

function getFile(fileId) {
  jQuery.ajax({
    url: my_ajax_object.ajax_url,
    type: 'POST',
    data: {
      fileId: fileId,
      action: 'get_file',
    },
    // 关键:指定接收二进制数据
    xhrFields: {
      responseType: 'blob'
    },
    success: function (blob) {
      displayPdf(blob)
    },
    error: function (x, y, z) {
      console.error(x, y, z)
    },
  })
}

3. 更新前端渲染函数

直接使用Blob对象传给PDF.js,转成ArrayBuffer后再处理:

function displayPdf(blob) {
  // 将Blob转为ArrayBuffer
  blob.arrayBuffer().then((arrayBuffer) => {
    pdfjsLib.getDocument({ data: arrayBuffer }).promise.then((pdf) => {
      pdf.getPage(1).then((page) => {
        const scale = 1.5;
        const viewport = page.getViewport({ scale: scale });

        const canvas = document.createElement("canvas");
        const context = canvas.getContext("2d");
        canvas.height = viewport.height;
        canvas.width = viewport.width;
        document.getElementById("pdf-container").appendChild(canvas);

        const renderContext = {
          canvasContext: context,
          viewport: viewport,
        };
        page.render(renderContext);
      });
    });
  });
}

更简化的替代方案

如果不需要用PDF.js渲染,直接在新窗口打开Blob:

function getFile(fileId) {
  jQuery.ajax({
    url: my_ajax_object.ajax_url,
    type: 'POST',
    data: {
      fileId: fileId,
      action: 'get_file',
    },
    xhrFields: {
      responseType: 'blob'
    },
    success: function (blob) {
      // 创建临时URL打开PDF
      const url = window.URL.createObjectURL(blob);
      window.open(url);
      // 释放资源
      setTimeout(() => window.URL.revokeObjectURL(url), 1000);
    },
    error: function (x, y, z) {
      console.error(x, y, z)
    },
  })
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 08:20:13