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

PHP调用YouTube API OAuth2超1小时运行的令牌续期方案

核心问题根因

你当前用的response_type=token是OAuth2隐式授权模式,天生适配不了后台长时跑的批处理任务:

  • 隐式流只会返回1小时有效期的access_token,不会返回可自动续期的refresh_token,令牌一过期必须人工重新跳转授权,没法自动续
  • 不带令牌调用走公开接口配额,单IP默认上限就是拉2万条左右;带令牌走授权用户配额虽然上限更高,但令牌过期就直接断,你现在拉8000条就失败,本质是令牌有效期内的请求额度打满+令牌到期双重限制,没有自动续期机制根本跑不完4万条。
改造步骤

1. 替换授权模式,首次授权后拿到长期有效的refresh_token

把你现在的隐式流授权改成授权码模式,加上离线权限申请,第一次人工授权完成后,就能拿到长期有效的refresh_token,后续季度跑任务不用再人工介入授权。
修改授权地址拼接代码:

// 注意补全https前缀,response_type改成code,加access_type=offline和prompt=consent参数,参数值记得urlencode
$iurl = "https://accounts.google.com/o/oauth2/auth?client_id=" . $client_id 
    . "&response_type=code&redirect_uri=" . urlencode($redirect_uri)
    . "&scope=" . urlencode($scopes)
    . "&access_type=offline&prompt=consent";

踩坑提醒:第一次跑这个授权跳转时,必须在弹出的授权页确认勾选YouTube数据读取权限,授权完成后Google会跳回你配置的回调地址,URL里会带code参数,拿这个code就能换令牌。返回结果里会同时有1小时有效期的access_token,和长期有效的refresh_token——只要你不主动撤销授权,这个refresh_token一直能用,把它存在本地配置文件/数据库里就行,整个流程只需要第一次人工操作这一次。

回调接口里用code换令牌的参考代码:

// 回调地址接收到URL里的code参数后执行
$code = $_GET['code'];
$tokenApi = "https://oauth2.googleapis.com/token";
$postData = [
    'code' => $code,
    'client_id' => $client_id,
    'client_secret' => $client_secret, // 从Google API控制台拿客户端密钥,隐式流用不上这个,现在必须配
    'redirect_uri' => $redirect_uri,
    'grant_type' => 'authorization_code'
];
$ch = curl_init($tokenApi);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
$tokenRes = json_decode(curl_exec($ch), true);
curl_close($ch);
// 把返回的refresh_token持久化存储,比如写到配置文件里,后续任务直接读取
$savedRefreshToken = $tokenRes['refresh_token'];
// 同时把首次拿到的access_token和过期时间存到本地缓存
file_put_contents('./token_cache.json', json_encode([
    'access_token' => $tokenRes['access_token'],
    'expire_at' => time() + $tokenRes['expires_in']
]));

2. 实现access_token自动续期逻辑,无需手动切换

在拉取视频的主逻辑入口,加一个统一获取有效令牌的方法,每次发请求前先检查本地缓存的access_token是不是快过期,过期就用存好的refresh_token自动换新,全程无人工干预:

function getValidAccessToken($clientId, $clientSecret, $savedRefreshToken) {
    // 读本地缓存的令牌信息
    $cachePath = './token_cache.json';
    $tokenCache = file_exists($cachePath) ? json_decode(file_get_contents($cachePath), true) : [];
    // 如果缓存的令牌还有5分钟以上有效期,直接返回使用,减少不必要的换令牌请求
    if (!empty($tokenCache['expire_at']) && $tokenCache['expire_at'] > time() + 300) {
        return $tokenCache['access_token'];
    }
    // 令牌过期,用refresh_token申请新的access_token
    $tokenApi = "https://oauth2.googleapis.com/token";
    $postData = [
        'refresh_token' => $savedRefreshToken,
        'client_id' => $clientId,
        'client_secret' => $clientSecret,
        'grant_type' => 'refresh_token'
    ];
    $ch = curl_init($tokenApi);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
    $newToken = json_decode(curl_exec($ch), true);
    curl_close($ch);
    // 新令牌写回缓存
    file_put_contents($cachePath, json_encode([
        'access_token' => $newToken['access_token'],
        'expire_at' => time() + $newToken['expires_in']
    ]));
    return $newToken['access_token'];
}

3. 拉取逻辑加容错,避免异常中断

分页拉取视频数据时,每次请求都调用上面的方法拿最新的有效令牌,同时加异常重试逻辑:

  • 单页拉取条数设为API支持的最大值50条,减少总请求数,省配额
  • 遇到401/403令牌失效错误时,强制清空本地令牌缓存,重新拉取新令牌后重试当前请求
  • 遇到429配额超限错误时,暂停2-3秒再重试,不要高频硬打接口
  • 已经拉取过的视频ID存本地,后续季度跑任务可以做增量拉取,不用每次都从头拉4万条,进一步省配额省时间
其他注意点
  • 第一次申请refresh_token必须加prompt=consent参数,不然Google不会返回refresh_token,只返回短期access_token,这点是高频踩坑点
  • client_secret和refresh_token都要存在服务器本地,不要对外泄露,否则其他人拿到可以越权操作你授权的账号
  • 提前在Google Cloud控制台给对应项目开启YouTube Data API v3权限,否则接口会报无权限错误
  • YouTube Data API v3单授权用户默认每日配额是10000单位,拉取单条视频元数据仅消耗1单位,拉4万条完全在配额范围内,只要令牌自动续期正常,不会出现拉到一半断的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 23:51:13