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

在gatsby-source-graphql的headers配置中异步生成并存储Bearer token

解决方案

方案1:内存缓存(推荐,适配绝大多数场景)

Gatsby 配置运行在 Node.js 进程中,你可以直接在模块作用域声明变量存储 token 和过期时间,单次构建/开发过程中所有请求都会复用同一份缓存,不需要重复调用鉴权接口,适配90%以上的使用场景。

修改后的getAuthToken代码如下:

require("dotenv").config({
  path: `.env.${process.env.NODE_ENV}`,
});

const axios = require("axios");

// 内存缓存变量
let cachedToken = null;
let tokenExpiryTime = 0;

const getAuthToken = async () => {
  const now = Date.now();
  // 缓存未过期直接返回
  if (cachedToken && now < tokenExpiryTime) {
    return cachedToken;
  }
  // Node.js 低版本兼容替换btoa为Buffer写法,兼容性更强
  const basicToken = Buffer.from(
    `${process.env.CTP_CLIENT_ID}:${process.env.CTP_CLIENT_SECRET}`
  ).toString('base64');
  try {
    const { data } = await axios.post(
      `${process.env.CTP_AUTH_URL}/oauth/token?grant_type=client_credentials`,
      null,
      {
        headers: {
          Authorization: `Basic ${basicToken}`,
        },
      }
    );
    cachedToken = `Bearer ${data.access_token}`;
    // 提前10分钟过期,避免临界时间使用失效token
    tokenExpiryTime = now + (data.expires_in - 600) * 1000;
    return cachedToken;
  } catch (err) {
    console.warn('获取鉴权token失败:', err);
    // 兜底逻辑:如果还有即将过期的旧token可以临时使用,也可以直接抛出错误终止构建
    if (cachedToken && now < tokenExpiryTime + 600 * 1000) {
      return cachedToken;
    }
    throw err;
  }
};

// 下方的module.exports配置保持原有逻辑即可,无需修改

方案2:本地文件缓存(支持多次构建复用)

如果需要重启 Gatsby 开发服务、多次执行构建命令时也不需要重新请求token,可以将token和过期时间写入本地临时文件缓存。

  1. 先在项目根目录.gitignore中添加一行.token.cache,避免缓存文件被提交到代码仓库泄露凭证
  2. 修改getAuthToken代码如下:
const fs = require('fs/promises');
const path = require('path');
const CACHE_FILE_PATH = path.resolve(__dirname, '.token.cache');

const getAuthToken = async () => {
  const now = Date.now();
  // 先读取本地缓存
  try {
    const cacheContent = await fs.readFile(CACHE_FILE_PATH, 'utf8');
    const { token, expiry } = JSON.parse(cacheContent);
    if (token && now < expiry) {
      return token;
    }
  } catch (e) {
    // 缓存不存在/解析失败直接忽略,重新请求即可
  }

  // 此处请求token的逻辑和方案1完全一致,请求成功后写入本地缓存
  // ... 请求逻辑省略
  const newToken = `Bearer ${data.access_token}`;
  const newExpiry = now + (data.expires_in - 600) * 1000;
  await fs.writeFile(CACHE_FILE_PATH, JSON.stringify({
    token: newToken,
    expiry: newExpiry
  }), 'utf8');
  return newToken;
};

内容的提问来源于stack exchange,提问作者Wojciech Jeleń

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 22:42:04