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

如何在React中实现API返回HTTP 401状态时触发弹窗显示

React中API返回401时触发全局弹窗的实现方案

1. 全局状态管理(用React Context实现)

先通过React Context创建全局状态,统一控制弹窗的显示/隐藏,避免在各个组件中重复维护状态:

// src/contexts/AuthContext.js
import { createContext, useContext, useState } from 'react';

const AuthContext = createContext();

export function AuthProvider({ children }) {
  const [showUnauthorizedModal, setShowUnauthorizedModal] = useState(false);

  // 触发弹窗的方法
  const triggerUnauthorizedModal = () => {
    setShowUnauthorizedModal(true);
  };

  // 关闭弹窗的方法
  const closeUnauthorizedModal = () => {
    setShowUnauthorizedModal(false);
  };

  return (
    <AuthContext.Provider value={{
      showUnauthorizedModal,
      triggerUnauthorizedModal,
      closeUnauthorizedModal
    }}>
      {children}
    </AuthContext.Provider>
  );
}

// 自定义Hook,方便组件快速调用上下文状态
export function useAuth() {
  return useContext(AuthContext);
}

2. 拦截API请求,捕获401状态码

以axios为例,添加响应拦截器统一处理API返回的401状态:

// src/utils/api.js
import axios from 'axios';
import { useAuth } from '../contexts/AuthContext';

// 创建axios实例
const api = axios.create({
  baseURL: '你的API基础地址',
});

// 初始化拦截器的函数(避免在拦截器中直接使用Hook的问题)
export function setupApiInterceptors() {
  const { triggerUnauthorizedModal } = useAuth();

  api.interceptors.response.use(
    (response) => response, // 请求成功直接返回响应
    (error) => {
      // 检测是否为401未授权状态
      if (error.response?.status === 401) {
        triggerUnauthorizedModal();
      }
      return Promise.reject(error);
    }
  );
}

export default api;

如果用原生fetch,可以封装统一的请求函数:

// src/utils/fetchWithAuth.js
import { useAuth } from '../contexts/AuthContext';

export async function fetchWithAuth(url, options = {}) {
  const response = await fetch(url, options);
  const { triggerUnauthorizedModal } = useAuth();
  
  if (response.status === 401) {
    triggerUnauthorizedModal();
  }
  return response;
}

3. 实现401提示弹窗组件

写一个基础弹窗组件,根据全局状态决定是否渲染:

// src/components/UnauthorizedModal.js
import { useAuth } from '../contexts/AuthContext';

export default function UnauthorizedModal() {
  const { showUnauthorizedModal, closeUnauthorizedModal } = useAuth();

  if (!showUnauthorizedModal) return null;

  return (
    <div style={{
      position: 'fixed',
      top: 0,
      left: 0,
      width: '100%',
      height: '100%',
      background: 'rgba(0,0,0,0.5)',
      display: 'flex',
      justifyContent: 'center',
      alignItems: 'center',
      zIndex: 9999
    }}>
      <div style={{
        background: '#fff',
        padding: '2rem',
        borderRadius: '8px',
        boxShadow: '0 3px 12px rgba(0,0,0,0.15)'
      }}>
        <h3>登录状态已失效</h3>
        <p>你的登录权限已过期,请重新登录后操作</p>
        <button onClick={closeUnauthorizedModal} style={{
          marginTop: '1.5rem',
          padding: '0.6rem 1.2rem',
          background: '#2563eb',
          color: '#fff',
          border: 'none',
          borderRadius: '4px',
          cursor: 'pointer'
        }}>
          我知道了
        </button>
      </div>
    </div>
  );
}

4. 在App组件中整合所有模块

最后在根组件中挂载Context Provider、初始化拦截器,并渲染弹窗:

// src/App.js
import { useEffect } from 'react';
import { AuthProvider, useAuth } from './contexts/AuthContext';
import UnauthorizedModal from './components/UnauthorizedModal';
import { setupApiInterceptors } from './utils/api';
// 导入你的业务页面组件
import Dashboard from './pages/Dashboard';

function AppContent() {
  useEffect(() => {
    // 初始化API拦截器
    setupApiInterceptors();
  }, []);

  return (
    <div className="App">
      <Dashboard />
      {/* 全局弹窗放在最外层,确保能覆盖所有内容 */}
      <UnauthorizedModal />
    </div>
  );
}

export default function App() {
  return (
    <AuthProvider>
      <AppContent />
    </AuthProvider>
  );
}

额外说明

  • 弹窗样式可以根据项目需求自定义,也可以直接使用Ant Design、Material UI等组件库的Modal组件简化开发;
  • 如果需要在弹窗中添加"跳转登录页"逻辑,只需在弹窗按钮的点击事件中添加路由跳转代码即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 12:01:04