# 网络错误与跨域问题

URL: https://caijiao.org/axios/troubleshooting/network-cors
Source: docs/axios/troubleshooting/network-cors.md
Description: 本章节介绍 Axios 在网络异常与跨域请求中的常见问题及解决方案，包括网络错误类型、超时与断网检测、跨域 CORS 原理、前端与后端的常见跨域配置、代理转发设置、以及应对 OPTIONS 预检请求的优化策略，帮助开发者彻底掌握 Axios 网络层调试与错误定位技巧。

在使用 Axios 请求后端接口时，常见问题包括**网络错误（Network Error）**与**跨域问题（CORS）**。理解这两类问题的原因与解决思路，是前端开发中非常重要的技能。

## 一、常见网络错误类型

Axios 可能抛出的网络错误主要包括：

| 错误类型              | 说明                                          |
| ----------------- | ------------------------------------------- |
| `ECONNABORTED`    | 请求超时（`timeout` 设置太短或网络慢）                    |
| `Network Error`   | 网络断开、DNS 解析失败或服务器拒绝连接                       |
| `ERR_BAD_REQUEST` | HTTP 状态码非 2xx（如 400, 404, 500）              |
| `ERR_CANCELED`    | 使用 `CancelToken` 或 `AbortController` 主动取消请求 |

示例：

```js
axios.get('/api/data', { timeout: 2000 })
  .then(res => console.log(res.data))
  .catch(err => {
    if (err.code === 'ECONNABORTED') {
      console.error('请求超时！');
    } else if (err.message.includes('Network Error')) {
      console.error('网络连接异常！');
    } else {
      console.error('其他错误：', err.message);
    }
  });
```

## 二、Axios 超时与断网检测

可以使用 `navigator.onLine` 检测网络状态，也可在响应错误中识别：

```js
window.addEventListener('offline', () => {
  console.warn('当前处于离线状态');
});
```

Axios 响应拦截器中检测断网：

```js
axios.interceptors.response.use(
  res => res,
  error => {
    if (!window.navigator.onLine) {
      console.error('网络断开，请检查网络连接');
    }
    return Promise.reject(error);
  }
);
```

## 三、跨域（CORS）问题的本质

跨域（Cross-Origin Resource Sharing）是浏览器安全策略限制导致的。
当前端与后端协议、域名或端口不同，浏览器会阻止跨源请求。

**跨域判定规则：**

* 协议不同（http ≠ https）
* 域名不同（example.com ≠ api.example.com）
* 端口不同（:3000 ≠ :8080）

浏览器在跨域请求前，会自动发起一个 **OPTIONS 预检请求（Preflight Request）**，用于确认服务端是否允许访问。

### 示例

```bash
OPTIONS /api/user HTTP/1.1
Origin: http://localhost:5173
Access-Control-Request-Method: GET
```

服务器响应：

```bash
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: http://localhost:5173
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
```

## 四、后端跨域配置示例

**Node.js（Express）**

```js
import express from 'express';
import cors from 'cors';

const app = express();
app.use(cors({
  origin: 'http://localhost:5173',
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  credentials: true
}));
```

**Spring Boot（Java）**

```java
@CrossOrigin(origins = "http://localhost:5173", allowCredentials = "true")
@RestController
public class UserController {
    @GetMapping("/api/user")
    public String user() { return "ok"; }
}
```

## 五、前端本地开发环境的代理解决方案

在本地前端开发中（例如使用 Vite、Webpack、Vue CLI），可以通过开发服务器代理转发请求到后端，避免浏览器跨域限制。

**Vite 配置示例（vite.config.js）**

```js
export default {
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        rewrite: path => path.replace(/^\/api/, '')
      }
    }
  }
};
```

访问 `http://localhost:5173/api/user` 时，Vite 将其代理到 `http://localhost:8080/user`。

**Webpack DevServer 配置**

```js
devServer: {
  proxy: {
    '/api': {
      target: 'http://localhost:8080',
      changeOrigin: true,
    }
  }
}
```

## 六、OPTIONS 预检请求优化

OPTIONS 请求不会携带业务参数，但会带来额外的延迟。优化策略包括：

1. **减少非简单请求**（只用 `GET/POST` 且 Content-Type 为 `application/x-www-form-urlencoded`）
2. **缓存预检结果**

   ```http
   Access-Control-Max-Age: 86400
   ```

   表示 24 小时内无需再次发起预检。
3. **在开发环境中使用代理**（避免真实跨域）

## 七、常见排查与调试技巧

1. **使用浏览器 DevTools → Network 查看 Request Headers**
   检查 `Origin`、`Access-Control-*` 是否正确。
2. **确认服务端返回状态码非 301/302**（重定向也会触发跨域失败）
3. **检查 HTTPS 与 HTTP 是否一致**
4. **服务端返回必须带上 `Access-Control-Allow-Origin`**
5. **避免设置 `withCredentials: true` 而服务端未返回 `Access-Control-Allow-Credentials: true`**

## 八、小结

Axios 的“Network Error”多数源于：

* 网络异常（断网、超时）
* 服务端不可达
* 跨域未正确配置

解决方案需结合浏览器控制台、网络面板与后端日志综合分析。
对于开发阶段跨域，推荐使用 **前端代理**；生产环境下，使用 **服务端 CORS 配置** 才是正确方式。
