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

使用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请求时的二进制内容处理错误,以及手动拼接请求体的格式风险,具体原因和修正方案如下:

错误原因

  1. 二进制数据被错误编码:直接将fileContent(Blob对象)拼接到字符串body中,Blob会被强制转换为UTF-8字符串,彻底破坏PDF的二进制结构——PDF是二进制文件,不能通过字符串拼接的方式传输。
  2. 手动拼接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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 23:03:07