
本文详解 react 组件中看似单次触发的 useeffect 实际导致两次 api 请求的常见原因,重点分析 cors 预检请求、axios 全局配置干扰等典型场景,并提供可验证的调试方法和替代方案。
本文详解 react 组件中看似单次触发的 useeffect 实际导致两次 api 请求的常见原因,重点分析 cors 预检请求、axios 全局配置干扰等典型场景,并提供可验证的调试方法和替代方案。
在 React 应用中,你可能会遇到这样一种“反直觉”现象:useEffect 仅执行一次(如 console.log('Enter in the useEffect') 只打印一次),但后端日志或网络面板却显示同一 API 被调用了两次。这并非 React 或 useEffect 的 bug,而是由浏览器行为或客户端配置引发的典型问题。下面我们将系统性地定位并解决它。
? 第一步:确认是否为 CORS 预检请求(最常见原因)
当你的前端(如 http://localhost:3000)与 API 服务(如 https://api.example.com)跨域时,浏览器会自动对满足特定条件的请求发起 CORS Preflight(OPTIONS 请求) —— 这是一种不携带业务数据、仅用于询问服务器是否允许实际请求的“探路”请求。
✅ 触发预检的典型条件包括:
- 使用自定义请求头(如
Authorization: Bearer xxx) - 使用非简单方法(如
PUT/DELETE),但GET本身不会触发;不过因含Authorization头,该axios.get()仍会触发预检 -
Content-Type不是application/x-www-form-urlencoded、multipart/form-data或text/plain
? 如何验证?
打开浏览器开发者工具 → Network 标签页 → 刷新页面 → 查看请求列表:
- 若看到一个
OPTIONS请求紧邻在你的GET /users之前,且状态码为200或204,则第二个“重复请求”实为预检请求,后端无需处理业务逻辑,也不应计入有效调用量。
? 提示:可在 Express 等后端框架中添加 cors 中间件并配置 optionsSuccessStatus: 200 显式支持预检,避免误判。
⚙️ 第二步:检查 Axios 全局配置或拦截器
Axios 的 interceptors.request 或 defaults 可能被多次注册(尤其在 HMR 热更新或模块重复导入时),导致同一请求被意外发送两次。
例如以下错误模式:
根据项目规范生成 React 和 Vue 组件,包括 TypeScript 类型定义、Ant Design 5 集成、Tailwind CSS 样式及 Vitest 测试文件。当用户提出创建、生成或搭建前端组件的需求时启用,例如:“帮我写一个表格组件”、“生成一个弹窗”、“create a form component”、“写一个列表页”、“生成一个下拉选择器”。该能力在以下任一场景触发:涉及 React/TSX/Vue 组件生成、UI 组件创建,或为组件生成测试文件。
// ❌ 危险:在组件或非单例模块中重复添加拦截器
axios.interceptors.request.use(config => {
console.log('Request intercepted'); // 此行可能打印两次
return config;
});
✅ 排查建议:
- 全局搜索
interceptors和axios.defaults,确保拦截器只在应用入口(如index.js)注册一次; - 临时替换为原生
fetch进行对照测试:useEffect(() => { if (!isSessionActive) return; const token = window.localStorage.getItem('token'); fetch(`${URL}/users`, { headers: { Authorization: `Bearer ${token}` } }) .then(res => res.json()) .then(data => setProfileData(data)) .catch(console.error); }, [isSessionActive]);若
fetch版本仅发出一次请求,则问题大概率出在 Axios 配置层。
✅ 最佳实践建议
服务端日志区分请求类型
在 API 日志中记录req.method,过滤掉OPTIONS请求,避免误统计 QPS。-
使用 React Query 等数据层库(推荐)
它内置防抖、缓存及请求去重机制,天然规避手动管理副作用的陷阱:const { data } = useQuery(['profile'], () => axios.get(`${URL}/users`, { headers: { Authorization: `Bearer ${token}` } }).then(res => res.data) ); 严格控制依赖数组
确保useEffect的依赖项稳定(如URL和isSessionActive是稳定引用),避免因依赖变动导致重复执行。
⚠️ 注意:
StrictMode(开发模式下默认启用)会故意双调用useEffect初始化函数(仅限开发环境),但这是模拟卸载/重挂载的检测机制,不会导致真实网络请求被执行两次——因为useEffect内部的if (!isSessionActive) return会阻止第二次执行。因此,若你在 Network 面板看到两个 真实 GET 请求,一定不是 StrictMode 导致。
通过以上三步排查,95% 的“双请求”问题可准确定位。核心原则是:先观察网络层原始流量,再逐层排除客户端干扰,最后优化数据获取架构。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










