api.js 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import axios from 'axios';
  2. // 1. 创建 axios 实例
  3. const api = axios.create({
  4. // 根据你的环境变量或硬编码地址
  5. baseURL: process.env.NEXT_PUBLIC_API_URL || 'http://45.137.220.138:8888',
  6. headers: {
  7. 'Content-Type': 'application/json',
  8. },
  9. });
  10. // 2. 请求拦截器:自动携带 Token
  11. api.interceptors.request.use(
  12. (config) => {
  13. // 仅在客户端执行时获取 token
  14. if (typeof window !== 'undefined') {
  15. const token = localStorage.getItem('rsid');
  16. if (token) {
  17. config.headers.Authorization = `Bearer ${token}`;
  18. }
  19. }
  20. return config;
  21. },
  22. (error) => {
  23. return Promise.reject(error);
  24. }
  25. );
  26. // 3. 响应拦截器:全局处理 401 自动跳转
  27. api.interceptors.response.use(
  28. (response) => {
  29. // 请求成功,直接返回
  30. return response;
  31. },
  32. (error) => {
  33. // 检查响应是否存在,且状态码是否为 401
  34. if (error.response && error.response.status === 401) {
  35. console.warn('Session expired or unauthorized (401). Cleaning up...');
  36. // 确保在浏览器端执行
  37. if (typeof window !== 'undefined') {
  38. // A. 清除本地存储的 Token 和用户信息
  39. localStorage.removeItem('rsid');
  40. localStorage.removeItem('user_info');
  41. // B. 触发 storage 事件,通知 Navbar 等组件更新状态 (变为未登录)
  42. window.dispatchEvent(new Event('storage'));
  43. // C. 强制跳转到登录页
  44. // 增加判断:如果当前已经在 /login 页面,就不需要跳转了,防止登录失败时死循环刷新
  45. if (!window.location.pathname.startsWith('/login')) {
  46. // 使用 window.location.href 强制跳转,确保页面状态彻底重置
  47. // 也可以使用 router.push('/login'),但 axios 外部拿不到 router 实例,href 最通用
  48. window.location.href = '/login';
  49. }
  50. }
  51. }
  52. // 继续抛出错误,以便组件内具体的 try/catch 也能捕获(比如显示"用户名密码错误")
  53. return Promise.reject(error);
  54. }
  55. );
  56. export default api;