文章目录
-
- 一、什么是"跨域"?
- 二、为什么浏览器要限制跨域?
-
- [1. 核心原因:安全防御](#1. 核心原因:安全防御)
- [**2. 历史背景**](#2. 历史背景)
- 三、哪些操作会触发跨域限制?
-
- [1. 受同源策略限制的操作](#1. 受同源策略限制的操作)
- [2. 不受限的跨域资源](#2. 不受限的跨域资源)
- 四、跨域问题的技术本质
-
- [1. 浏览器的双重验证](#1. 浏览器的双重验证)
- [2. 常见错误场景](#2. 常见错误场景)
- [五、为什么移动端/Postman 没有跨域问题?](#五、为什么移动端/Postman 没有跨域问题?)
- 六、解决跨域的四种方式
-
- [6.1 JSONP(仅限 GET 请求)](#6.1 JSONP(仅限 GET 请求))
- [6.2 前端代理(开发环境常用)](#6.2 前端代理(开发环境常用))
- [6.3 后端配置 CORS(生产环境推荐)](#6.3 后端配置 CORS(生产环境推荐))
- [6.4 Nginx 反向代理(生产环境高效方案)](#6.4 Nginx 反向代理(生产环境高效方案))
- [6.5 对比总结](#6.5 对比总结)
一、什么是"跨域"?
当浏览器向 不同源(Origin) 的服务器发起请求时,就会触发跨域限制。判断"同源"需同时满足以下三项:
- 协议相同(HTTP/HTTPS)
- 域名相同(www.example.com)
- 端口相同(80/443)
❌ 以下均为跨域示例:
http://a.com→https://a.com(协议不同)https://a.com→https://api.a.com(子域名不同)https://a.com:80→https://a.com:8080(端口不同)
二、为什么浏览器要限制跨域?
1. 核心原因:安全防御
同源策略是为了防止恶意网站:
- 窃取用户数据
例:攻击者在页面嵌入脚本,偷偷访问用户的银行网站(假设用户已登录)。 - CSRF 攻击
利用用户 Cookie 伪造请求(如转账操作)。
2. 历史背景
- 早期 Web 没有同源策略,导致 XSS/CSRF 攻击泛滥
- 1995 年由 Netscape 浏览器首次引入,现成所有浏览器的标准
三、哪些操作会触发跨域限制?
1. 受同源策略限制的操作
| 操作类型 | 示例 | 是否跨域限制 |
|---|---|---|
| AJAX 请求/Fetch 请求 | fetch('https://api.com/data') |
✅ 受限 |
| Web 字体 | @font-face加载外部字体 |
✅ 受限 |
| Cookie/LocalStorage | 读取其他域的存储 | ✅ 受限 |
| drawImage() | 绘制其他域的图片 | ✅ 受限 |
| WebGL 贴图 | 加载其他域的 3D 模型 | ✅ 受限 |
2. 不受限的跨域资源
| 资源类型 | 原因 |
|---|---|
<img>/<script>/<link> |
历史遗留,但要求服务端不返回敏感数据 |
| 跨域 CSS | 需确保Content-Type: text/css |
四、跨域问题的技术本质
1. 浏览器的双重验证
当发起跨域请求时:
-
预检请求(Preflight)
对复杂请求(如带自定义头的 POST),浏览器先发
OPTIONS请求询问服务器是否允许跨域。bashOPTIONS /data HTTP/1.1 Origin: https://your-site.com Access-Control-Request-Method: POST -
服务端响应 CORS 头
服务器必须返回明确的许可头:
httpAccess-Control-Allow-Origin: https://your-site.com Access-Control-Allow-Methods: POST, GET
2. 常见错误场景
- 后端未配置 CORS 头:返回数据但被浏览器拦截
- 证书不匹配:HTTPS 页面请求 HTTP 接口
- 复杂请求未处理预检 :如带
Authorization头的 API
五、为什么移动端/Postman 没有跨域问题?
- 浏览器是唯一执行者
同源策略是浏览器行为,Postman/cURL/手机 App 直接发送 HTTP 请求,不受限制。 - Native App 无同源策略
安卓/iOS 应用可自由请求任意 API(但需自行处理安全问题)。
六、解决跨域的四种方式
6.1 JSONP(仅限 GET 请求)
原理 :利用 <script> 标签不受同源策略限制的特性,通过动态创建脚本实现跨域请求。
特点:
- 仅支持 GET 请求。
- 需要服务端配合返回回调函数包裹的数据(如
callback(data))。
示例代码:
javascript
function jsonp(url, callbackName) {
const script = document.createElement("script");
script.src = `${url}?callback=${callbackName}`;
document.body.appendChild(script);
window[callbackName] = (data) => {
console.log(data);
document.body.removeChild(script);
};
}
jsonp("http://api.example.com/data", "handleData");
适用场景:老旧浏览器兼容、简单数据获取。
6.2 前端代理(开发环境常用)
原理 :在开发环境中,前端服务器(如 Vite/Webpack)代理请求到后端,绕过浏览器同源限制。
特点:
- 仅用于开发环境。
- 无需后端配合,前端配置即可。
配置示例(Vite):
js
// vite.config.js
export default {
server: {
proxy: {
"/api": {
target: "http://api.example.com",
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, "")
}
}
}
};
适用场景:本地开发调试。
6.3 后端配置 CORS(生产环境推荐)
原理 :服务端通过设置响应头 Access-Control-Allow-Origin 允许指定域名的跨域请求。
关键响应头:
bash
Access-Control-Allow-Origin: * // 允许所有域名(或指定域名)
Access-Control-Allow-Methods: GET,POST,PUT // 允许的请求方法
Access-Control-Allow-Headers: Content-Type // 允许的请求头
Access-Control-Allow-Credentials: true // 允许携带Cookie(需前端配合)
后端示例(Node.js):
js
res.setHeader("Access-Control-Allow-Origin", "https://your-frontend.com");
res.setHeader("Access-Control-Allow-Methods", "GET,POST");
适用场景:生产环境跨域请求。
6.4 Nginx 反向代理(生产环境高效方案)
原理 :通过 Nginx 配置反向代理,将跨域请求转发到目标服务器,并添加 CORS 头。
配置示例:
bash
server {
listen 80;
server_name your-frontend.com;
location /api {
proxy_pass http://api.example.com;
add_header 'Access-Control-Allow-Origin' 'https://your-frontend.com';
add_header 'Access-Control-Allow-Methods' 'GET,POST';
add_header 'Access-Control-Allow-Headers' 'Content-Type';
}
}
优势:
- 高性能,无需修改后端代码。
- 可统一管理跨域策略。
适用场景:生产环境多服务跨域。
6.5 对比总结
| 方案 | 适用场景 | 请求类型 | 是否需要后端配合 | 安全性 |
|---|---|---|---|---|
| JSONP | 老旧项目兼容 | GET | 是 | 低 |
| 前端代理 | 开发环境 | 所有 | 否 | 中 |
| 后端 CORS | 生产环境 | 所有 | 是 | 高 |
| Nginx 代理 | 生产环境 | 所有 | 否(运维配置) | 高 |
👉点击进入 我的网站