清晰易懂的跨域请求知识——拿捏
1. 什么是跨域请求?
- 简单来说:当你的 前端网页(例如
http://frontend.com
)通过 JavaScript 调用 后端接口(例如http://backend.com/api
)时,如果两者的 域名、端口、协议 中任意一项不同,浏览器会认为这是「跨域请求」,默认会阻止请求(出于安全考虑)。 - 核心限制:这个限制是由浏览器的 同源策略(Same-Origin Policy) 触发的,目的是防止恶意网站窃取用户数据。
2. 什么是「同源」?
- 同源的定义:两个 URL 的以下三项必须完全相同:
- 协议(如
http
vshttps
) - 域名(如
frontend.com
vsapi.frontend.com
) - 端口(如
80
vs8080
)
- 协议(如
- 举例:
- 前端:
http://localhost:3000
- 后端:
http://localhost:8080
- 不同源!因为端口不同(3000 vs 8080)。
- 前端:
3. 为什么前后端分离会触发跨域问题?
在前后端分离架构中:
- 前端:独立部署在一个服务器(如
http://frontend.com:3000
)。 - 后端:独立部署在另一个服务器(如
http://backend.com:8080
)。 - 问题:前端通过 JavaScript(如
fetch
或axios
)调用后端接口时,浏览器会拦截请求,并报错:Access to fetch at 'http://backend.com:8080/api/data' from origin 'http://frontend.com:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
4. 如何解决跨域问题?
方法 1:后端配置 CORS(推荐)
- CORS(跨域资源共享):后端在响应头中添加允许跨域的规则。
- 示例(以 Node.js 为例):
// 后端代码 const express = require('express'); const app = express();// 添加 CORS 头 app.use((req, res, next) => {res.header('Access-Control-Allow-Origin', 'http://frontend.com:3000'); // 允许前端的域名res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); // 允许的请求方法res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization'); // 允许的请求头next(); });app.get('/api/data', (req, res) => {res.json({ message: 'Hello from backend!' }); });app.listen(8080);
方法 2:前端代理(开发环境常用)
- 原理:让前端服务器(如
webpack-dev-server
)代理请求到后端,隐藏跨域。 - 示例(React 项目配置):
- 在
package.json
中添加代理:{"proxy": "http://backend.com:8080" }
- 前端代码直接请求
/api/data
(而不是写完整后端地址):fetch('/api/data') // 实际请求会转发到 http://backend.com:8080/api/data.then(response => response.json());
- 在
方法 3:JSONP(历史方案,已淘汰)
- 原理:利用
<script>
标签不受跨域限制的特性(仅支持 GET 请求)。 - 示例:
// 前端 function handleResponse(data) {console.log(data); } const script = document.createElement('script'); script.src = 'http://backend.com:8080/api/data?callback=handleResponse'; document.body.appendChild(script);// 后端返回 handleResponse({ message: 'Hello from JSONP!' });
5. 实际场景示例
场景 1:前端调用后端 API
- 前端代码(React):
// 前端运行在 http://localhost:3000 fetch('http://localhost:8080/api/data').then(response => response.json()).then(data => console.log(data));
- 后端代码(Spring Boot):
@RestController @CrossOrigin(origins = "http://localhost:3000") // 允许前端跨域 public class DataController {@GetMapping("/api/data")public String getData() {return "Hello from backend!";} }
场景 2:浏览器报错示例
如果后端未配置 CORS,浏览器会拦截响应并提示:
Access to fetch at 'http://localhost:8080/api/data' from origin 'http://localhost:3000'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present.
6. 总结
- 跨域的本质:浏览器为了安全限制不同源的请求。
- 解决方法:
- 后端配置 CORS(生产环境推荐)。
- 前端代理(开发环境常用)。
- JSONP(已淘汰,仅作了解)。
- 关键点:跨域是浏览器的行为,后端接口本身可以被调用,但需要明确告知浏览器允许跨域。