使用Drive API在GAS中将Google Docs转PDF生成异常求助
问题:Google Apps Script中使用Drive API转换Docs为PDF后上传文件异常
我尝试使用Drive API在Google Apps Script(GAS)中将Google Docs文件转换为PDF,步骤如下:
- 获取Docs文件
- 转换为PDF
- 上传至Drive
我采用export接口获取并转换Docs为PDF,再通过create接口上传,代码如下:
function test(){ let service = getOAuthService(); service.reset(); // Get the Docs file let url = encodeURI("https://www.googleapis.com/drive/v3/files/<id of file>/export?mimeType=application/pdf&supportsAllDrives=true"); let docFile = getGoogleAPI(url); var fileName = "my-test-file.pdf"; var fileContent = docFile.getBlob(); var fileMetadata = { name: fileName, parents: ["<id of parent folder>"], mimeType: "application/pdf" }; url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&supportsAllDrives=true"; var header = { "Authorization": "Bearer " + service.getAccessToken(), "Content-Type": "multipart/related; boundary=<BOUNDARY_STRING>" }; var body = "--<BOUNDARY_STRING>\r\n" + "Content-Type: application/json; charset=UTF-8\r\n\r\n" + JSON.stringify(fileMetadata) + "\r\n" + "--<BOUNDARY_STRING>\r\n" + "Content-Type: application/pdf\r\n\r\n" + fileContent + "\r\n" + "--<BOUNDARY_STRING>--"; let response = UrlFetchApp.fetch(url, { method: "post", headers: header, payload: body, muteHttpExceptions: true }); var responseJson = JSON.parse(response.getContentText()); if (response.getResponseCode() == 200) { Logger.log("File uploaded successfully with ID: " + responseJson.id); } else { Logger.log("Error uploading file: " + responseJson.error.message); } }
但生成的PDF文件要么为空,要么格式不正确无法预览。我认为获取Docs并转换的环节正常,问题出在上传环节,可能是编码错误?请问我哪里出错了?
解答
你的核心问题出在手动构造multipart请求时的二进制内容处理错误,以及手动拼接请求体的格式风险,具体原因和修正方案如下:
错误原因
- 二进制数据被错误编码:直接将
fileContent(Blob对象)拼接到字符串body中,Blob会被强制转换为UTF-8字符串,彻底破坏PDF的二进制结构——PDF是二进制文件,不能通过字符串拼接的方式传输。 - 手动拼接multipart请求易出错:手动设置boundary、换行符时很容易出现格式偏差(比如边界字符串不一致、换行符不规范),导致服务端无法正确解析请求内容。
修正方案
方案一:用DriveApp简化实现(推荐)
如果不需要严格使用Drive API,GAS内置的DriveApp可以直接完成Docs转PDF并上传的操作,代码更简洁且不易出错:
function testWithDriveApp() { const docId = "<你的Docs文件ID>"; const folderId = "<目标文件夹ID>"; const fileName = "my-test-file.pdf"; // 获取Docs文件并导出为PDF Blob const docFile = DriveApp.getFileById(docId); const pdfBlob = docFile.getAs("application/pdf"); // 上传到指定文件夹并设置文件名 const newPdfFile = DriveApp.getFolderById(folderId) .createFile(pdfBlob) .setName(fileName); Logger.log("文件上传成功,ID:" + newPdfFile.getId()); }
方案二:修正Drive API的上传逻辑
如果必须使用Drive API,需要通过UrlFetchApp的数组式payload自动处理multipart请求,避免手动拼接:
function testWithDriveAPI() { let service = getOAuthService(); service.reset(); const accessToken = service.getAccessToken(); const docId = "<你的Docs文件ID>"; const folderId = "<目标文件夹ID>"; const fileName = "my-test-file.pdf"; // 1. 导出Docs为PDF Blob const exportUrl = `https://www.googleapis.com/drive/v3/files/${docId}/export?mimeType=application/pdf&supportsAllDrives=true`; const exportOptions = { headers: { "Authorization": `Bearer ${accessToken}` }, muteHttpExceptions: true }; const exportResponse = UrlFetchApp.fetch(exportUrl, exportOptions); // 检查导出是否成功 if (exportResponse.getResponseCode() !== 200) { const error = JSON.parse(exportResponse.getContentText()); Logger.log("导出PDF失败:" + error.error.message); return; } const pdfBlob = exportResponse.getBlob(); // 2. 用multipart方式上传(让GAS自动处理boundary和编码) const uploadUrl = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&supportsAllDrives=true"; const fileMetadata = { name: fileName, parents: [folderId], mimeType: "application/pdf" }; // 构造payload数组,分别传入元数据和二进制内容 const payload = [ { contentType: "application/json", content: JSON.stringify(fileMetadata) }, { contentType: "application/pdf", content: pdfBlob.getBytes() // 传递二进制字节数组,避免编码问题 } ]; const uploadOptions = { method: "post", headers: { "Authorization": `Bearer ${accessToken}` }, payload: payload, muteHttpExceptions: true }; const uploadResponse = UrlFetchApp.fetch(uploadUrl, uploadOptions); const responseJson = JSON.parse(uploadResponse.getContentText()); if (uploadResponse.getResponseCode() === 200) { Logger.log("文件上传成功,ID:" + responseJson.id); } else { Logger.log("文件上传失败:" + responseJson.error.message); } }
关键修正点
- 放弃手动拼接multipart请求:使用UrlFetchApp的数组格式payload,GAS会自动生成正确的boundary和请求头,确保内容格式合法。
- 传递二进制字节数组:通过
pdfBlob.getBytes()获取PDF的原始二进制数据,避免字符串编码对二进制内容的破坏。 - 增加导出环节的错误检查:先确认PDF导出成功,再执行上传操作,避免处理无效数据。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

