如何在网页浏览器中展示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); }); }); }
问题原因及解决方法
核心问题
- AJAX接收的是字符串而非二进制数据:默认jQuery AJAX会把响应解析为字符串,而PDF是二进制格式,直接转
Uint8Array会导致数据损坏。 - 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
相关产品推荐
相关产品推荐

