在做网页开发时,前端页面和后端接口不在同一个域名下,是最常见的跨域场景。比如你在本地开发前端项目,地址是 http://localhost:3000,而接口跑在 http://api.example.com,浏览器就会拦下请求,提示跨域错误。
为什么会出跨域问题
这其实是浏览器出于安全考虑实施的同源策略。简单说,协议、域名、端口只要有一个不同,就算非同源,浏览器默认不允许 ajax 拿数据。服务器本身其实并不限制,问题出在浏览器这一层。
后端怎么解决跨域
最常用的方案是在后端响应头里加上允许跨域的字段。比如用 Node.js 的 Express 框架,可以这样写:
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
next();
});
如果是 Java Spring Boot 项目,可以在控制器类或方法上加 @CrossOrigin 注解:
@CrossOrigin(origins = "http://localhost:3000")
@RestController
public class UserController {
@GetMapping("/user")
public User getUser() {
return new User("zhangsan");
}
}
生产环境注意点
开发阶段为了方便,可能直接设置 Access-Control-Allow-Origin 为 *,表示允许所有来源。但在正式上线时,建议明确指定可信的前端域名,避免安全风险。比如只给 https://www.myapp.com 开通权限。
还有一种情况是带 cookie 的请求,这时候前端发请求要加上 withCredentials: true,后端也得配合设置:
res.header('Access-Control-Allow-Origin', 'https://www.myapp.com');
res.header('Access-Control-Allow-Credentials', 'true');
不然浏览器照样会拒绝响应数据。
预检请求是怎么回事
当你发的是复杂请求,比如 Content-Type 是 application/json,或者带了自定义 header,浏览器会先发一个 OPTIONS 请求探路,看看后端支不支持。这个叫预检请求。后端得正确响应这个 OPTIONS 请求,返回 200,不然真正的请求根本发不出去。
有些框架默认不处理 OPTIONS,就得手动加个中间件:
app.options('/*', (req, res) => {
res.sendStatus(200);
});
遇到跨域问题别慌,先看浏览器控制台报什么错,再检查响应头有没有缺字段,一步步对就行。多数时候就是少加了一两个 header 而已。