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

搭配Cognito用户池认证的React集成AWS API Gateway及token异常处理流程是怎样的

处理AWS Cognito Token过期与Axios请求流程方案

问题根因说明

AWS API Gateway集成Cognito授权器后,Token过期、无效时默认返回401 Unauthorized状态码,此类仅返回网络错误无明确提示的问题,通常是两个原因导致:

  1. API Gateway的CORS配置未放开401状态码与错误头的跨域暴露,前端无法识别正常的401响应,将其归类为跨域网络错误
  2. Axios自定义配置将401状态码判定为网络异常,未进入响应错误拦截逻辑

前置配置修正(先解决过期提示无法识别问题)

  • 登录AWS API Gateway控制台,进入对应API的Cognito授权器配置,自定义未授权响应模板,返回体包含"message": "Token is Expired"明确提示
  • 调整API的CORS规则,在Access-Control-Expose-Headers中添加WWW-Authenticate、x-amzn-ErrorType字段,允许401状态码的跨域返回
  • 保留Axios默认的validateStatus配置,仅将2xx状态码判定为成功响应,确保401可以正常进入响应错误拦截器

Axios全流程封装方案

以下方案基于AWS Amplify封装Cognito操作(也可自行替换为原生Cognito接口调用逻辑)

1. 初始化自定义Axios实例

import axios from 'axios';
import { Auth } from 'aws-amplify'; //  Amplify会自动管理Cognito会话、Token存储

const apiClient = axios.create({
  baseURL: '你的AWS API Gateway服务地址',
  timeout: 10000,
  validateStatus: (status) => status >= 200 && status < 300, // 仅2xx判定为成功响应
});

2. 请求拦截器统一注入Token

apiClient.interceptors.request.use(
  async (config) => {
    try {
      // Amplify的currentSession会自动校验Token有效性,过期时优先用Refresh Token刷新
      const session = await Auth.currentSession();
      const idToken = session.getIdToken().getJwtToken();
      // 注入授权头,名称需和API Gateway Cognito授权器配置的头名称一致,默认为Authorization
      config.headers.Authorization = idToken;
      return config;
    } catch (err) {
      // 无法获取有效会话,直接跳转登录页
      window.location.href = '/login';
      return Promise.reject(err);
    }
  },
  (error) => Promise.reject(error)
);

3. 响应拦截器处理Token过期逻辑

// 标记是否正在刷新Token,避免重复调用刷新接口
let isRefreshing = false;
// 存储刷新Token期间排队的请求
let pendingRequests = [];

apiClient.interceptors.response.use(
  (response) => response.data, // 正常响应直接返回数据
  async (error) => {
    const originalRequest = error.config;
    // 判定为Token过期:返回401且当前请求未重试
    if (error.response?.status === 401 && !originalRequest._retry) {
      if (isRefreshing) {
        // 正在刷新Token,将当前请求加入队列等待
        return new Promise(resolve => {
          pendingRequests.push((newToken) => {
            originalRequest.headers.Authorization = newToken;
            resolve(apiClient(originalRequest));
          });
        });
      }

      originalRequest._retry = true;
      isRefreshing = true;

      try {
        // 触发Token刷新,Amplify自动用Refresh Token换取新的ID Token
        const session = await Auth.currentSession();
        const newIdToken = session.getIdToken().getJwtToken();
        // 更新全局默认授权头
        apiClient.defaults.headers.common.Authorization = newIdToken;
        // 执行所有排队的请求
        pendingRequests.forEach(callback => callback(newIdToken));
        pendingRequests = [];
        // 重试当前失败的请求
        return apiClient(originalRequest);
      } catch (refreshErr) {
        // 刷新失败说明Refresh Token也已过期,清空会话跳转登录
        await Auth.signOut();
        window.location.href = '/login';
        return Promise.reject(refreshErr);
      } finally {
        isRefreshing = false;
      }
    }

    // 其他错误直接抛出给业务层处理
    return Promise.reject(error);
  }
);

4. 封装通用请求方法适配各类请求

// GET请求
export const get = (url, params = {}, config = {}) => {
  return apiClient.get(url, { params, ...config });
};

// POST请求
export const post = (url, data = {}, config = {}) => {
  return apiClient.post(url, data, config);
};

// PUT请求
export const put = (url, data = {}, config = {}) => {
  return apiClient.put(url, data, config);
};

// DELETE请求
export const del = (url, params = {}, config = {}) => {
  return apiClient.delete(url, { params, ...config });
};

5. 业务层使用示例

import { get, post } from './封装的axios文件路径';

// 调用GET接口
const fetchUserInfo = async () => {
  try {
    const userInfo = await get('/user/detail', { userId: 1001 });
    console.log('用户信息', userInfo);
  } catch (err) {
    console.error('请求失败', err);
  }
};

// 调用POST接口
const createOrder = async (orderData) => {
  try {
    const result = await post('/order/create', orderData);
    console.log('创建成功', result);
  } catch (err) {
    console.error('创建失败', err);
  }
};

额外优化点

  • 可在请求拦截器注入Token前,本地校验Token的exp时间戳,若已过期直接触发刷新逻辑,减少一次无效请求
  • 若不使用AWS Amplify,可自行调用Cognito的InitiateAuth接口传入Refresh Token换取新的ID/Access Token
  • 敏感场景下建议Token存储在sessionStorage而非localStorage,降低XSS攻击泄露风险

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 14:45:03