Axios 如何跨域携带 Cookie?
一、什么是跨域?核心是"同源策略"
1. 同源的定义
同源:协议、域名、端口三者完全一致才算同源,否则就是跨域。
场景 | 前端页面URL | 后端接口URL | 是否跨域 |
---|---|---|---|
同源 | http://localhost:3000 | http://localhost:3000/api | 否 |
不同端口 | http://localhost:3000 | http://localhost:8080/api | 是 |
不同域名 | www.a.com | api.b.com | 是 |
不同协议 | http://localhost:3000 | https://localhost:3000/api | 是 |
注意:即使 IP 相同,只要域名不同,也算跨域。
2. 为什么有跨域限制?
- 同源策略是浏览器的安全机制,防止恶意网站窃取用户数据(如 Cookie)。
- 跨域请求默认不会携带 Cookie,也不能访问非同源的 DOM。
二、跨域时的典型问题:Cookie 无法携带
1. 典型场景
- 前端:
web.example.com
- 后端:
api.example.com
- 登录后后端
Set-Cookie: token=xxx; Domain=api.example.com
- 问题:前端属于
web.example.com
,Cookie 作用域是api.example.com
,浏览器不会自动携带 Cookie。
2. 常见报错
ruby
The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
三、Axios 跨域携带 Cookie 的完整解决方案
1. 前端配置(withCredentials)
推荐做法:统一封装 Axios 实例,强制 withCredentials: true
js
import axios from 'axios';
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000,
withCredentials: true, // 关键
});
export default api;
或在单个请求中:
js
axios.get('https://api.example.com/user/profile', {
withCredentials: true
});
2. 后端 CORS 配置(以 Express 为例)
关键点:
Access-Control-Allow-Origin
必须是具体域名,不能是*
Access-Control-Allow-Credentials: true
- Cookie 设置
SameSite=None; Secure; Domain=.example.com
js
const cors = require('cors');
app.use(cors({
origin: 'https://web.example.com', // 不能是 *
credentials: true
}));
app.post('/login', (req, res) => {
res.cookie('token', 'abc123', {
httpOnly: true,
secure: true, // 生产环境必须 https
sameSite: 'None', // 跨域必须 None
domain: '.example.com' // 子域共享
});
res.json({ success: true });
});
3. Cookie 属性设置
属性 | 说明 |
---|---|
domain | .example.com ,子域共享 |
path | / ,全站有效 |
httpOnly | true,防止 XSS |
secure | true,必须 HTTPS |
sameSite | None,跨域必须设置 |
4. 开发环境代理(绕过跨域)
Vue CLI 代理示例:
js
// vue.config.js
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'https://api.example.com',
changeOrigin: true,
secure: false,
pathRewrite: { '^/api': '' }
}
}
}
};
前端请求 /api/user/profile
,实际代理到 https://api.example.com/user/profile
。
注意:仅限开发环境,生产环境必须用 CORS。
5. 第三方 API 跨域(不可控后端)
方案:服务端中转
js
// Node.js 代理
app.get('/proxy', async (req, res) => {
const result = await axios.get('https://third-party.com/data');
res.send(result.data);
});
前端请求自己的 /proxy
,由服务端转发。
四、常见错误与安全注意事项
- 不能用
Access-Control-Allow-Origin: *
搭配 Cookie - Cookie 必须
SameSite=None
且Secure=true
才能跨域 - 生产环境强制 HTTPS
- 限制允许的方法和请求头,避免安全隐患
五、总结表
步骤 | 说明 |
---|---|
前端 withCredentials | 必须设置 withCredentials: true |
后端 CORS | Access-Control-Allow-Origin 指定前端域名,credentials: true |
Cookie 属性 | SameSite=None; Secure; Domain=.example.com |
生产环境 | 必须 HTTPS |
开发环境 | 可用代理,生产必须 CORS |
六、最佳实践建议
- 生产环境后端精确配置 CORS
- Cookie 设置合适的
domain
、sameSite
、secure
- 前端统一封装 Axios,强制
withCredentials
- 建议用 JWT 替代 Cookie(减少跨域复杂度)
七、常见问题答疑
Q1:为什么 withCredentials 必须配合后端 CORS?
A:否则浏览器会拦截响应,Cookie 不会被设置。
Q2:为什么 SameSite=None 必须 Secure?
A:浏览器安全要求,防止 Cookie 被劫持。
*Q3:能不能用通配符 ?
A:不能,带 Cookie 的跨域请求必须指定具体域名。
八、流程图
css
前端(web.example.com) --withCredentials--> 后端(api.example.com)
| |
|<--Set-Cookie: SameSite=None; Secure----|
| |
|<--Access-Control-Allow-Origin: web.example.com
|<--Access-Control-Allow-Credentials: true
九、参考代码片段
前端:
js
axios.post('https://api.example.com/login', data, {
withCredentials: true
});
后端:
js
res.cookie('token', 'abc123', {
sameSite: 'None',
secure: true,
domain: '.example.com'
});
res.header('Access-Control-Allow-Origin', 'https://web.example.com');
res.header('Access-Control-Allow-Credentials', 'true');
十、结论
- 跨域携带 Cookie,前端
withCredentials: true
,后端 CORS 配置+Cookie 属性必须正确。 - 生产环境务必用 HTTPS,开发环境可用代理。
- 推荐 JWT 方案,减少跨域 Cookie 的复杂度。