GMAIL API获取的PDF附件渲染乱码且文件大小不符,该如何解决?
GMAIL API获取的PDF附件渲染乱码且文件大小不符,该如何解决?
看起来你踩了一个开发者常遇到的坑——把二进制文件当成纯文本处理了!你现在的解码方式虽然解决了“无法打开”的问题,但因为Base64解码后直接转成字符串写入文件,导致二进制数据被损坏,才会出现乱码和文件大小不符的情况。
问题根源
你用Base64.atob(str)得到的是UTF-8字符串,但PDF是纯二进制格式,里面包含很多无法用UTF-8正确表示的字节。当字符串被写入文件时,这些异常字节会被替换成占位符,直接破坏了PDF的结构,自然打开就是乱码,文件大小也和原文件不一样。
解决方案:用Node.js原生Buffer处理二进制数据
Node.js的Buffer是专门用来处理二进制数据的,我们可以先把Gmail API返回的URL安全Base64转换成标准Base64,再用Buffer.from()生成二进制缓冲区,最后直接写入文件,这样就能完美保留原始数据了。
修改你的代码如下:
- 替换原有的
decodeBase64函数,改成返回二进制Buffer:
// 把URL安全Base64转成标准Base64,再生成二进制Buffer function decodeBase64ToBuffer(str) { // 替换Gmail API返回的URL安全Base64特殊字符 const standardBase64 = str.replace(/_/g, '/').replace(/-/g, '+'); // 直接生成二进制Buffer,这才是PDF的原始数据 return Buffer.from(standardBase64, 'base64'); }
- 修改文件写入逻辑,直接写入Buffer而不是字符串:
getAttachment(messageId, attachmentId, auth).then(attachmentData => { const pdfBuffer = decodeBase64ToBuffer(attachmentData.data); // 写入Buffer确保二进制数据完整无损坏 fs.writeFile(part.filename, pdfBuffer, (err) => { if (err) { console.error('保存PDF失败:', err); } else { console.log(`PDF文件 ${part.filename} 已成功保存!`); } }); });
更优雅的async/await写法
如果你的代码已经在用async/await,建议用fs.promises.writeFile让代码更简洁易读:
async function savePdfAttachment(messageId, attachmentId, filename, auth) { try { const attachmentData = await getAttachment(messageId, attachmentId, auth); const standardBase64 = attachmentData.data.replace(/_/g, '/').replace(/-/g, '+'); const pdfBuffer = Buffer.from(standardBase64, 'base64'); await fs.promises.writeFile(filename, pdfBuffer); console.log(`文件 ${filename} 保存成功!`); } catch (error) { console.error('处理附件时出错:', error); } } // 直接调用函数即可 savePdfAttachment(messageId, attachmentId, part.filename, auth);
这样处理后,你保存的PDF应该就和邮箱里的原文件完全一致,打开也不会乱码了。
备注:内容来源于stack exchange,提问作者SpaceMan Spiff
相关产品推荐
相关产品推荐

