理解跨域及 Nginx 解决跨域的配置详解
理解跨域及 Nginx 解决跨域的配置详解
在前后端分离的开发中,跨域问题是我们经常遇到的坑之一。很多新手开发者第一次接触到跨域时,可能会感到困惑:“为什么我的前端请求明明写得没问题,却总是报错?”今天我们就来聊聊什么是跨域、为什么会有跨域问题,以及如何通过 Nginx 配置来优雅地解决它。
什么是跨域?
跨域(Cross-Origin Resource Sharing, CORS) 是指浏览器阻止从一个域名下的网页向另一个域名发起请求的一种安全机制。简单来说,如果你的前端页面运行在 http://example.com
,但后端接口的地址是 http://api.example.com
,这时就属于跨域请求。
什么样的请求算跨域?
如果以下任一项不同,就算是跨域请求:
- 协议(http 和 https 是不同的协议)
- 域名(如
example.com
和api.example.com
) - 端口(如
http://example.com:8080
和http://example.com:3000
)
为什么会有跨域限制?
跨域问题是浏览器的同源策略(Same-Origin Policy)引起的。同源策略是浏览器的一种安全机制,目的是为了防止恶意网站窃取用户的敏感数据。
但是在实际开发中,前端和后端分开部署非常普遍,跨域访问几乎不可避免。那么,如何优雅地解决这个问题呢?答案就是 CORS。
CORS 是如何解决跨域的?
CORS(跨域资源共享)是一种让服务端声明哪些资源可以被哪些源访问的机制。浏览器在发送跨域请求前,会先发起一个 预检请求(Preflight Request),询问服务器是否允许跨域。
常见的 CORS 响应头
服务端通过设置以下 HTTP 响应头来控制跨域访问:
-
Access-Control-Allow-Origin
指定允许访问资源的域。例如:*
表示允许所有域访问,https://example.com
表示仅允许特定域访问。 -
Access-Control-Allow-Methods
指定允许的 HTTP 方法,例如:GET, POST, PUT, DELETE
。 -
Access-Control-Allow-Headers
指定允许的自定义请求头,例如:Authorization, Content-Type
。 -
Access-Control-Allow-Credentials
指定是否允许发送凭据(如 Cookies)。值为true
时表示允许。 -
Access-Control-Max-Age
指定预检请求的结果缓存时间(单位:秒)。
如何通过 Nginx 配置解决跨域?
Nginx 是我们常用的反向代理工具,也是解决跨域问题的利器。下面我们具体看看如何通过 Nginx 配置来应对跨域。
1. 简单的跨域配置
如果你的需求是让所有前端页面都可以访问后端接口,可以配置如下:
server {
listen 80;
server_name api.example.com;
location / {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
add_header Access-Control-Allow-Headers Content-Type,Authorization;
add_header Access-Control-Allow-Credentials true;
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_pass http://backend_service;
}
}
说明:
Access-Control-Allow-Origin *
:允许所有域名访问。Access-Control-Allow-Methods
:指定支持的请求方法。Access-Control-Allow-Headers
:允许的自定义请求头,比如Content-Type
或Authorization
。Access-Control-Allow-Credentials
:允许发送 Cookies 和 HTTP 认证信息。- OPTIONS 请求处理:浏览器的预检请求是 OPTIONS 请求,返回
204
表示成功。
2. 限制特定域名的跨域访问
如果你只希望特定域名可以访问,可以这样配置:
server {
listen 80;
server_name api.example.com;
location / {
set $cors_origin "";
if ($http_origin = "http://frontend.example.com") {
set $cors_origin "http://frontend.example.com";
}
add_header Access-Control-Allow-Origin $cors_origin;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
add_header Access-Control-Allow-Headers Content-Type,Authorization;
add_header Access-Control-Allow-Credentials true;
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_pass http://backend_service;
}
}
说明:
$http_origin
是浏览器发送的请求头中的Origin
值。- 通过判断
$http_origin
,动态设置允许的域名。
3. 配置允许 Cookies 的跨域
如果需要支持跨域时携带 Cookies,需要同时配置服务端和前端。
Nginx 配置:
server {
listen 80;
server_name api.example.com;
location / {
add_header Access-Control-Allow-Origin http://frontend.example.com;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
add_header Access-Control-Allow-Headers Content-Type,Authorization;
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_pass http://backend_service;
}
}
前端配置:
在 Axios 或 Fetch 请求中加上 withCredentials: true
:
axios.get('http://api.example.com/data', {
withCredentials: true
});
实际场景案例
1. 前端本地开发
场景:前端通过 localhost:3000
访问后端的 api.example.com
。
Nginx 配置:
server {
listen 80;
server_name api.example.com;
location / {
add_header Access-Control-Allow-Origin http://localhost:3000;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
add_header Access-Control-Allow-Headers Content-Type,Authorization;
add_header Access-Control-Allow-Credentials true;
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_pass http://backend_service;
}
}
总结
通过本文,我们了解了跨域的原理和 CORS 的基本概念,并学习了如何通过 Nginx 配置解决跨域问题。无论是简单的全局开放,还是动态控制特定域名、支持 Cookies 的跨域,都可以通过灵活的 Nginx 配置来实现。
跨域问题看似棘手,其实只要理解其原理,就不难解决。如果你还有什么疑问或想分享自己的经验,欢迎留言讨论! 😊