05 · 网络 / axios / 代理

0 阅读2分钟

本项目 axios 封装见 ../frontend/src/api/client.js

5.1 Network Error / ERR_CONNECTION_REFUSED

原因:后端没起或端口不对。

定位:

解决:

cd backend && uv run python run.py --port 9002

5.2 Request failed with status code 401

原因:token 失效 / 没带上。

定位:

最佳实践:

  • 401 在响应拦截器统一处理:清 token、跳登录页、避免每个调用方各自判断
  • 不要在每个 API 调用里手动加 token,统一在拦截器里加

5.3 跨域 CORS

症状:浏览器报 Access-Control-Allow-Origin 不允许。

原因:dev 走代理就不应该有跨域。如果出现,八成是 axios baseURL 写了完整域名绕过了代理。

修法:

// ❌ 绕过代理,直接打到 9002,触发 CORS
axios.create({ baseURL: 'http://localhost:9002/api' });

// ✅ 走 Vite 代理
axios.create({ baseURL: '/api' });

生产环境的跨域要后端配 CORS 中间件或 nginx 加响应头。

5.4 文件下载 / 二进制响应被当 JSON 解析

axios 默认 responseType: 'json',下载二进制会乱码。

修法:

axios.get('/api/export.xlsx', { responseType: 'blob' })
  .then(res => {
    const url = URL.createObjectURL(res.data);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'export.xlsx';
    a.click();
    URL.revokeObjectURL(url);
  });

5.5 上传文件 Content-Type 错误

误区:手动设 Content-Type: multipart/form-data,漏掉 boundary,后端解析失败。

修法:

// ✅ 让浏览器自动加 boundary
const fd = new FormData();
fd.append('file', file);
axios.post('/api/upload', fd); // 不要手动设 Content-Type

5.6 axios 超时:timeout of 0ms exceeded

默认 axios 不超时,长时间挂起。建议:

axios.create({ timeout: 30000 });

但流式响应、大文件上传要单独跳过超时。

5.7 并发请求竞态:后发的先返回,UI 显示旧数据

场景:搜索框快速输入,后请求被先请求覆盖。

修法:

  • 用 AbortController 取消旧请求:
    const ctrl = new AbortController();
    axios.get('/api/search', { signal: ctrl.signal });
    // 下次发请求前 ctrl.abort()
    
  • 用请求 id 比对,只取最新

5.8 SSE / 长轮询断连

现象:EventSource 连接 30 秒后断开。

原因:nginx / 代理服务器默认空闲超时 30-60 秒。

修法:

  • nginx 加 proxy_read_timeout 3600s; proxy_buffering off;
  • 前端 onerror 里自动重连
  • 服务端定期发心跳事件保活

5.9 WebSocket 断连重连

09-Yjs协同.md

5.10 请求被浏览器扩展拦截

某些广告拦截器 / 隐私扩展会拦截带 trackanalytics 的 URL,导致 ERR_BLOCKED_BY_CLIENT

定位:隐身模式复现一次,排除扩展问题。