关于Nginx的跨域请求(CORS)

详解Nginx中CORS跨域请求的配置方法,包括核心指令说明、预检请求处理、完整配置示例,帮助你轻松解决前后端分离场景下的跨域问题。

当你的网站(比如 https://a.com)想要请求另一个不同域名下的资源时(比如 API 服务器 https://api.b.com),浏览器出于安全考虑,会默认阻止这次请求。
在 Nginx 中配置 CORS,就等于在服务器的大门口给这个请求盖上一个“允许通行”的章。

一、为什么需要配置 CORS?

简单来说,就是为了解决“跨域资源共享”的问题。最常见的场景:

  • 前后端分离:前端项目部署在 https://www.your-domain.com,后端 API 服务部署在 https://api.your-domain.com
  • 调用外部 API:你的网站需要直接从浏览器请求第三方提供的 API 资源。

如果没有 CORS 配置,浏览器控制台就会无情地抛出类似这样的错误:
Access to XMLHttpRequest at '…' from origin '…' has been blocked by CORS policy…

二、核心配置指令

在 Nginx 中,我们主要使用 add_header 指令来添加 CORS 相关的 HTTP 响应头。

响应头说明示例
Access-Control-Allow-Origin(最重要!) 允许哪个源(域名)可以访问我。* (允许任何域名,慎选!) https://www.a.com (只允许 https://www.a.com)
Access-Control-Allow-Methods允许的 HTTP 请求方法。GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers允许的自定义请求头。Content-Type, Authorization, X-Requested-With
Access-Control-Allow-Credentials是否允许发送 Cookie。true (注意:当为 true 时, Access-Control-Allow-Methods不能*)

三、什么是“预检”请求 (Preflight)?

对于一些“非简单请求”(比如 PUTDELETE 请求,或者带了自定义请求头的 POST 请求),浏览器会先发送一个 OPTIONS 方法的“预检”请求,来问问服务器:“我待会儿要用这个姿势(方法和请求头)请求你,你支持吗?”
服务器需要正确响应这个 OPTIONS 请求,告诉浏览器“我支持”,然后浏览器才会发送真正的请求。所以,我们的 Nginx 配置必须能处理这种 OPTIONS 请求。

注意:只要是跨域请求,就需要配置 CORS 相关 header,跨域请求又分简单请求和非简单请求,非简单请求才会在正式请求之前发送预检请求

四、配置示例

下面是一个非常实用且考虑了安全性和预检请求的配置。你可以把它放在 Nginx 配置文件(如 nginx.confsites-available/your-site)的 serverlocation 块中。

# 将此段配置放在你的 server 或 location 块中
# 例如: location /api/ { ... }

# ---------------- CORS 配置开始 ----------------

# 1. 设置允许跨域的源 (域名)
# 为了安全,强烈建议指定你的前端域名,而不是使用 "*"
add_header 'Access-Control-Allow-Origin' "https://www.your-frontend.com" always;

# 2. 设置允许的请求方法
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;

# 3. 设置允许的请求头
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, X-Requested-With' always;

# 4. 设置是否允许携带 Cookie
# 如果你的前端需要传递 cookie, 请设置为 true
# 注意: 当 Access-Control-Allow-Origin 不是 "*" 时,这个才生效
add_header 'Access-Control-Allow-Credentials' 'true' always;

# 5. 处理 "预检" (Preflight) 请求
# 当请求方法为 OPTIONS 时,直接返回 204 (No Content),表示预检成功
# 浏览器收到 204 后,才会发送真正的业务请求
if ($request_method = 'OPTIONS') {
    # 预检请求的有效期,单位秒。在此期间,浏览器无需为同一请求再次发送预检。
    add_header 'Access-Control-Max-Age' 1728000;
    add_header 'Content-Type' 'text/plain; charset=utf-8';
    add_header 'Content-Length' 0;
    return 204;
}

# ---------------- CORS 配置结束 ----------------

# 你原来的其他配置,比如 proxy_pass
# proxy_pass http://backend_server;

示例说明:

  1. 处理预检请求:通过 if ($request_method = 'OPTIONS') 判断,如果是预检请求,就直接返回 204 状态码,并附上 CORS 相关的头信息,然后中断请求,不再转发给后端服务。这样可以减轻后端服务的压力。
  2. always 参数:在 add_header 指令的末尾加上 always 是个好习惯,它可以确保无论响应状态码是什么(比如 404, 500),这些 CORS 头部都会被添加,从而给前端更明确的调试信息。

五、如何使用?

  1. 找到你的网站对应的 Nginx 配置文件。
  2. 将上述配置示例代码块复制到合适的 server { ... }location / { ... } 中。
  3. 修改域名!将 www.your-frontend.com 替换成你自己的前端应用域名。
  4. 检查 Nginx 配置语法是否正确: sudo nginx -t
  5. 重新加载 Nginx 配置使其生效: sudo nginx -s reload

现在,你的 Nginx 已经成功配置好 CORS,可以愉快地进行跨域请求了!

Licensed under CC BY-NC-SA 4.0