You need to enable JavaScript to run this app. 使用Trigger与Apex类获取Google Drive访问令牌报405错误的问题求助
优惠活动
大模型
产品
解决方案
定价
更多

使用Trigger与Apex类获取Google Drive访问令牌报405错误的问题求助

核心问题根因
  • 你误将OAuth 2.0权限范围地址https://www.googleapis.com/auth/drive当作获取访问令牌的POST请求端点,这个地址仅用于声明接口调用的权限范围,本身不支持POST方法,直接调用就会抛出405错误。
  • 令牌请求参数完全不符合Google OAuth规范:未指定授权类型,错误传入username参数,Content-Type设置错误(令牌接口要求表单格式提交,不支持JSON格式直接提交)。
  • 代码存在变量作用域问题:createFolder静态方法中引用的accessToken未定义,即便成功获取令牌也无法正常传递给创建文件夹的请求。
  • 若要固定自动获取指定Google账号的访问令牌,纯Web OAuth授权流需要用户手动跳转授权一次,更适配的方案是用Google服务账号模式,无需用户交互即可长期操作指定Drive。
修正实现方案

基础规范纠正

Google获取访问令牌的固定端点为https://oauth2.googleapis.com/token,而非权限范围地址。
针对你固定操作指定Drive账号的需求,优先选择以下两种无交互授权模式之一:

  1. 服务账号模式:在Google Cloud Console创建服务账号,给服务账号分配对应Drive的操作权限(共享盘直接授权即可,个人Drive需要配置域范围委托),纯后端即可申请令牌,无需用户参与。
  2. 授权码+刷新令牌模式:手动完成一次OAuth授权拿到长期有效的刷新令牌,后续直接用刷新令牌换新的访问令牌即可,不需要重复用户交互。

修正后参考代码

public class GDriveFolderCreationClass {
    // 敏感信息请存储在Salesforce命名凭据/受保护自定义元数据中,禁止硬编码在代码内
    private final String clientId = '你的应用客户端ID';
    private final String clientSecret = '你的应用客户端密钥';
    private final String refreshToken = '你手动获取的长期刷新令牌';

    public class DeserializeTokenResponse {
        public String access_token;
        public Integer expires_in;
    }

    public String getAccessToken() {
        DeserializeTokenResponse resp;
        String tokenEndpoint = 'https://oauth2.googleapis.com/token';
        // 按表单格式构造请求参数,对参数做URL编码避免特殊字符错误
        String reqBody = 'grant_type=refresh_token'
                        + '&client_id=' + EncodingUtil.urlEncode(clientId, 'UTF-8')
                        + '&client_secret=' + EncodingUtil.urlEncode(clientSecret, 'UTF-8')
                        + '&refresh_token=' + EncodingUtil.urlEncode(refreshToken, 'UTF-8');
        
        Http http = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndpoint(tokenEndpoint);
        req.setMethod('POST');
        // 令牌接口要求表单提交格式,不要设置为JSON
        req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
        req.setBody(reqBody);
        
        HttpResponse res = http.send(req);
        if (res.getStatusCode() == 200 && String.isNotBlank(res.getBody())) {
            resp = (DeserializeTokenResponse) JSON.deserialize(res.getBody(), DeserializeTokenResponse.class);
            return resp.access_token;
        }
        System.debug('令牌获取失败,响应内容:' + res.getBody());
        return null;
    }

    @future(callout=true)
    public static void createFolderInDrive(String folderName) {
        GDriveFolderCreationClass instance = new GDriveFolderCreationClass();
        String accessToken = instance.getAccessToken();
        createFolder(accessToken, folderName);
    }

    public static void createFolder(String accessToken, String folderName) {
        if (String.isBlank(accessToken)) {
            System.debug('访问令牌为空,终止文件夹创建流程');
            return;
        }
        HttpRequest req = new HttpRequest();
        req.setMethod('POST');
        req.setEndpoint('https://www.googleapis.com/drive/v3/files');
        req.setHeader('Authorization', 'Bearer ' + accessToken);
        req.setHeader('Content-Type', 'application/json');
        // 对文件夹名称做转义,避免JSON格式异常
        String reqBody = '{"name": "' + String.escapeSingleQuotes(folderName) + '", "mimeType": "application/vnd.google-apps.folder"}';
        req.setTimeout(60000);
        req.setBody(reqBody);

        Http http = new Http();
        HttpResponse res = http.send(req);
        System.debug('文件夹创建响应:' + res.getBody());
    }
}

Auth Provider配置排查点

  • 确认Google侧Connected App的重定向URI和Salesforce Auth Provider中配置的回调URL完全一致,无斜杠、协议(http/https)不匹配问题。
  • 授权申请时传入的scope参数包含https://www.googleapis.com/auth/drive,不要将该scope地址配置为回调URL。
  • 授权成功后要保存返回的长期刷新令牌,后续用刷新令牌换访问令牌即可,不需要重复走用户授权流程。

内容的提问来源于stack exchange,提问作者pranav

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.01 19:06:07