Blob转换的PDF字符串转可下载PDF失败,求技术解决方案
下载从Blob转换的PDF字符串后无法打开,提示“Failed to load document”
需求目标
我有一个从Blob转换而来的PDF字符串(从服务器传递到客户端),希望点击下载按钮后将其保存为可正常打开的PDF文档。
服务端转换代码
当前将Blob转换为PDF字符串的代码:
const downloadBlobToString = async (containerClient: any, blobName: any) => { const blobClient = await containerClient.getBlobClient(blobName); const downloadResponse = await blobClient.download(0); const downloaded = await streamToBuffer(downloadResponse.readableStreamBody); return downloaded.toString(); };
问题描述
文件能正常下载,但打开时提示“Failed to load document”(无法加载文档)。
示例PDF字符串
%PDF-1.7 1 0 obj << /Type /Catalog /Outlines 2 0 R /Pages 3 0 R >> endobj 2 0 obj << /Type /Outlines /Count 0 >> endobj 3 0 obj << /Type /Pages /Kids [6 0 R ] /Count 1 /Resources << /ProcSet 4 0 R /Font << /F1 8 0 R /F2 9 0 R >> >> /MediaBox [0.000 0.000 612.000 792.000] >> endobj 4 0 obj [/PDF /Text ] endobj 5 0 obj << /Producer (��dompdf 1.0.2 + CPDF) /CreationDate (D:20221216202946+00'00') /ModDate (D:20221216202946+00'00') /Title (��Untitled Spreadsheet) /Author (��Unknown Creator) >> endobj 6 0 obj << /Type /Page /MediaBox [0.000 0.000 612.000 792.000] /Parent 3 0 R /Contents 7 0 R >> endobj 7 0 obj << /Filter /FlateDecode /Length 822 >> stream x����N�@��y��zil��mn�Ҫ��P��—��:����Q; ;�j{�-��&3��;�<QBJ ���zb�0���Z��V���װ��b"w����>b�r�N����M�oQ�J4��%�R-�w�Y!���j���>*X#*�����8��x�J(�`:��4(��������E�z|s �S8�N:)Ф���J4ʼ����U#�Lk��f#ccS���P�g�E�w��];��gp���sY g|��Zho1x��m�7M��+�YGww��28~f���*X|�.��()��)�ǡ��;�҃O�=��t-�N����� V���/�3����j�;�C{a����@�������Dx>���n8��nS����;ٔ9"�%G�Ғ#8m�kCqY � qi�J(�+�A�C���+��O-A�%r�� ݵ!� �+x�^���9�<\�^�ۛ�ͪ�tޟ �=�d���;��>�Tً?`��I�ptΨp��GۺH��B��z@���z����a=��6�Ġ�hQw�+���@a��ӦK6�m@qC�$.��W�Mzp�J���P�`��A�hC�UJ(�y�0|����_=��_m[�>#���r��E��=T���!v�J �������`���v�:}s�Bo��絨R�P!�z�Q)�g��8�w��~�PΔ)%@��H�z52&n�p"�0'*p�}��]d�8��.����g�q'���=v��J�����j�3Y.�,����Qgn=�xq?���߁I'U �GD�����݀�� endstream endobj 8 0 obj << /Type /Font /Subtype /Type1 /Name /F1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding >> endobj 9 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Times-Roman /Encoding /WinAnsiEncoding >> endobj 10 0 obj [6 0 R /Fit] endobj xref 0 11 0000000000 65535 f 0000000009 00000 n 0000000074 00000 n 0000000120 00000 n 0000000284 00000 n 0000000313 00000 n 0000000557 00000 n 0000000660 00000 n 0000001554 00000 n 0000001661 00000 n 0000001770 00000 n trailer << /Size 11 /Root 1 0 R /Info 5 0 R /ID[<73c60b8a58a461322f732d1e85a77dd1><73c60b8a58a461322f732d1e85a77dd1>] >> startxref 1799 %%EOF
已尝试的前端解决方案
方案一
const downloadPDF01 = (data: any) => { console.log(data); const binaryString = window.atob(data); const binaryLen = binaryString.length; const bytes = new Uint8Array(binaryLen); for (let i = 0; i < binaryLen; i++) { const ascii = binaryString.charCodeAt(i); bytes[i] = ascii; } const blob = new Blob([bytes], { type: 'application/pdf' }); const link = document.createElement('a'); link.href = window.URL.createObjectURL(blob); link.download = 'downloadedPdf'; link.click(); };
方案二
const url = window.URL.createObjectURL(new Blob([data])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', 'downloadedfile.pdf'); //or any other extension document.body.appendChild(link); link.click();
问题原因
核心问题出在服务端的转换逻辑:直接调用downloaded.toString()将二进制Buffer转为字符串会损坏PDF的二进制数据。PDF是二进制文件,包含很多非UTF-8/ASCII的字节,直接转字符串会导致字节丢失或编码错乱,最终生成的文件无法被PDF阅读器识别。
解决方案
1. 修正服务端代码:传递Base64编码的字符串
将Buffer转为Base64字符串,这是二进制数据在字符串中安全传递的标准方式:
const downloadBlobToString = async (containerClient: any, blobName: any) => { const blobClient = await containerClient.getBlobClient(blobName); const downloadResponse = await blobClient.download(0); const downloaded = await streamToBuffer(downloadResponse.readableStreamBody); // 替换toString()为base64编码 return downloaded.toString('base64'); };
2. 修正前端代码:解码Base64并生成Blob
使用方案一的逻辑,但确保服务端传递的是Base64字符串,此时window.atob()可以正确解码:
const downloadPDF = (base64Data: string) => { const binaryString = window.atob(base64Data); const bytes = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { bytes[i] = binaryString.charCodeAt(i); } const blob = new Blob([bytes], { type: 'application/pdf' }); const link = document.createElement('a'); link.href = window.URL.createObjectURL(blob); link.download = 'downloaded.pdf'; document.body.appendChild(link); link.click(); // 清理URL对象,避免内存泄漏 window.URL.revokeObjectURL(link.href); document.body.removeChild(link); };
如果不想使用Base64,也可以让服务端直接返回Blob的二进制流,前端直接处理响应,但如果必须通过字符串传递,Base64是唯一可靠的方式。
内容的提问来源于stack exchange,提问作者user22104593
相关产品推荐
相关产品推荐

