Nginx(15)-快速解决CORS问题

本文详细解释了CORS机制,包括同源策略的定义,CORS请求的分类(简单请求和非简单请求),处理流程,以及Nginx中如何配置CORS以支持跨域。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        CORS是一个W3C标准,全称是跨域资源共享(Cross-Origin Resource Sharing)。它允许浏览器向跨源服务器,发出XML HttpRequest(XHR) 或Fetch API跨域 HTTP 请求,从而克服了同源使用的限制。

        CORS 需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,整个 CORS 通信过程,浏览器自动完成,不需要用户参与。CORS 对开发者透明,CORS 通信与同源的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附件的头信息,有时还会多处一次附件的请求,但用户不会有感觉。

目录

CORS机制

同源策略

CORS请求分类

简单请求CORS处理

非简单请求CORS处理

CORS相关头字段

Nginx的CORS配置


CORS机制

同源策略

        同源策略是一个重要的web安全策略,它用于限制一个源的资源如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。

        同源指两个 URL 的协议(Protocol)、主机(Host)、端口(Port)都相同,否则是不同源的。例如:

# 下面两个同源
http://www.example.com/a
http://www.example.com/b
# 同上不同源情况
# 协议不同
https://www.example.com/a
# 域名不同
http://trial.example.com/a
# 端口不同
http://www.example.com:8080/a

        不同源的请求就需要CORS支持。 

CORS请求分类

        浏览器将 CORS 请求分成两类:简单请求和非简单请求。

        简单请求是http请求同时满足以下条件的http请求:

  1. 请求方法是以下三种之一:HEAD、GET、POST
  2. HTTP 的头信息不超出以下几种字段:Accept、Accept-Language、Content-Language、Content-Type、DPR、Downlink、Save-Data、Viewport-Width、Width
  3. Content-Type 的值仅限于三种之一:text/plain、multipart/form-data、application/x-www-form-urlencoded

        不是简单请求,就只能是 非简单请求

简单请求CORS处理

简单请求跨域处理过程:

1、浏览器直接发出 CORS 请求。在头信息之中,增加一个 Origin 字段,用来说明本次请求来自哪个源(协议 + 主机 + 端口)。

2、服务器接收到请求,查看Origin 指定的源,如果在许可范围内,服务器会返回一个正确的 HTTP 响应,在响应头加入Access-Control-Allow-Origin字段。否则,服务器会返回 HTTP 响应则不包含Access-Control-Allow-Origin字段

3、浏览器收到响应头,判断响应头是否包含Access-Control-Allow-Origin字段,包含且值正确,那就正常处理,否则就抛出CORS错误

非简单请求CORS处理

        非简单请求的 CORS 请求,相对于简单请求,会在正式通信之前,增加一次 HTTP 查询请求,即预检请求(preflight):浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些 HTTP 方法和头信息字段。只有得到肯定答复,浏览器才会发出正式的 XMLHttpRequest 请求,否则就报错。

        “预检请求”用的请求方法是 OPTIONS,表示这个请求是用来询问的。头信息包括如下变量:

  • Origin:必须字段。来说明本次请求来自哪个源(协议 + 主机 + 端口)
  • Access-Control-Request-Method:必须字段,用来列出浏览器的 CORS 请求会用到哪些 HTTP 方法。
  • Access-Control-Request-Headers:可选字段(内容是逗号分隔的字符串),指定浏览器 CORS 请求会额外发送的头信息字段。
  • Access-Control-Max-Age:预检请求结果缓存有效期。有效期内,CORS请求不需再发预检请求,直接使用缓存数据。如果不缓存,则每次都会发送预检请求。

        服务器收到“预检请求”以后,检查了 Origin、Access-Control-Request-Method 和 Access-Control-Request-Headers 字段以后,确认允许跨域请求,就可以做出回应。如果服务器否定了“预检请求”,会返回一个正常的 HTTP 回应,但是没有任何的 CORS 相关的头信息字段。这是,浏览器就认定,服务器不同意预检请求,因此触发一个错误。

CORS相关头字段

 Access-Control-Allow-Origin :支持CORS的必须字段。值要么是请求时 Origin 字段的值,要么是一个 *,表示接受任意的源(域名)的请求。

Access-Control-Allow-Credentials:可选字段。值为布尔值,表示是否允许请求发送 Cookie。默认情况下,Cookie 不包括在 CORS 请求之中。设为 true,即表示服务器明确许可,Cookie 可以包含在请求中,一起发给服务器。如果发送Cookie真正起作用,还需满足:

1、必须在 客户端请求中打开 withCredentials 属性:xhr.withCredentials = true。否则,即使服务器同意发送 Cookie,浏览器也不会发送。

2、Access-Control-Allow-Origin 就不能设为 *,必须指定明确的、与请求网页一致的域名。同时,Cookie 依然遵循同源策略,只有用服务器域名设置的 Cookie 才会上传,其他域名的 Cookie 并不会上传,且(跨源)原网页代码中的 document.cookie 也无法读取服务器域名下的 Cookie。

Access-Control-Allow-Headers:前端向后端传递数据时,除默认请求头字段外,可通过该字段给出的字段来传递。默认包含请求头字段有:Accept, Accept-Language, Content-Language, Content-Type(只接受:application/x-www-form-urlencoded、multipart/form-data 或 text/plain 这三种 MIME 类型。)

Access-Control-Expose-Headers:可选字段。CORS 请求时,后端向前端传递数据时(getResponseHeader() 方法只能获取),除默认响应头字段外,可通过该头字段给出的字段来传递。默认包含响应头字段有:: Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。字段值可以配置为通配符“*”(不包括Authorization),但请求不能携带凭据(请求没有Cookie或认证信息),否则,就成了普通字符“*”。

Nginx的CORS配置

Nginx支持跨域请求配置,示例配置如下:

# cors请求方法分组,结果记录到$cors_method
map $request_method $cors_method {
    GET 1;
    POST 1;
    OPTIONS 11;  # 预检请求方法
    default 0; # 非前面三种请求方法,不做处理
}
server {
    location / {
        # 简单请求
        if ($cors_method = '1') {
            add_header 'Access-Control-Allow-Origin'  '*.example.com';
            add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Headers''token,Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
            add_header 'Access-Control-Expose-Headers' 'Authorization, Refresh-Token';
        }
        # 复杂请求-预检请求处理
        if ($cors_method = '11') {
            add_header 'Access-Control-Allow-Origin'  '*.example.com';
            add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT';
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Headers''token,Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
            add_header 'Access-Control-Expose-Headers' 'Authorization, Refresh-Token';
            # 缓存1天
            add_header 'Access-Control-Max-Age' 86400;
            # 状态码204表示请求已经执行成功,但没有内容。浏览器不会刷新页面,也不会导向别的页面。
            return 204;
        }
    }
    ...
}

实际配置不需要按示例进行,只要按需处理即可。

如果涉及多出处配置CORS,则配置单独成文件,在使用位置直接include进来。这样配置更简洁。

这篇文章如果对您有所帮助或者启发的话,帮忙关注或点赞,有问题请评论,必有所复。您的支持是我写作的最大动力!

<think>嗯,用户想了解如何通过配置Nginx反向代理来解决跨域资源共享(CORS问题。首先,我需要回顾一下CORS的基本概念和常见问题CORS是浏览器的一种安全机制,当不同源的资源请求时会被阻止。常见的解决方案包括后端设置响应头或者使用反向代理。 根据用户提供的引用资料,特别是引用[1]、[2]、[3]、[4],Nginx反向代理可以通过配置特定的响应头来解决这个问题。例如,添加Access-Control-Allow-Origin、Access-Control-Allow-Methods等头信息。引用[4]提到需要先删除重复的响应头,再重新添加,这可能是因为后端服务器可能已经设置了这些头,导致冲突。 接下来,我需要整理出具体的配置步骤。首先,配置反向代理的基本设置,将前端请求代理到后端服务器。然后,处理OPTIONS预检请求,因为跨域请求可能会先发送OPTIONS来检查权限。之后,添加必要的CORS响应头,同时注意删除可能重复的头信息,如引用[4]所述。 用户可能还关心最佳实践,比如安全性考虑。例如,允许所有来源(*)可能在开发环境中方便,但生产环境应指定具体域名。另外,处理OPTIONS请求时返回204状态码,避免不必要的处理。 需要确保配置的语法正确,比如在location块中添加正确的add_header指令,并使用proxy_hide_header来删除重复的头。同时,考虑到缓存问题,是否需要添加Cache-Control头或其他相关头信息。 最后,验证配置是否正确,可以通过重启Nginx并测试跨域请求是否成功。用户可能还需要了解如何调试,比如检查响应头是否正确,或者查看Nginx的错误日志。 总结下来,步骤应该是:配置反向代理、处理预检请求、添加CORS头、删除重复头、安全优化、测试验证。同时,提供相关的问题,帮助用户进一步理解和解决可能遇到的问题。</think>### 通过Nginx反向代理解决CORS问题的配置方法 #### 1. **基础反向代理配置** 首先设置反向代理,将前端请求转发到后端服务器: ```nginx server { listen 80; server_name example.com; location /api/ { proxy_pass http://backend-server:8080/; # 后端服务地址 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } ``` 通过`proxy_pass`将`/api/`路径的请求代理到后端服务[^3]。 #### 2. **处理OPTIONS预检请求** 浏览器在跨域请求前会发送`OPTIONS`预检请求,需单独处理: ```nginx location /api/ { if ($request_method = OPTIONS) { add_header Access-Control-Allow-Origin "*"; add_header Access-Control-Allow-Methods "GET, POST, OPTIONS"; add_header Access-Control-Allow-Headers "Content-Type, Authorization"; add_header Access-Control-Max-Age 1728000; # 预检结果缓存时间(秒) return 204; # 空响应 } # 其他请求继续转发 proxy_pass http://backend-server:8080/; } ``` 此处直接返回预检响应,避免后端处理OPTIONS请求[^2][^4]。 #### 3. **添加CORS响应头** 在代理响应中添加必要的跨域头信息: ```nginx location /api/ { proxy_pass http://backend-server:8080/; # 删除后端可能重复设置的CORS头 proxy_hide_header Access-Control-Allow-Origin; proxy_hide_header Access-Control-Allow-Methods; proxy_hide_header Access-Control-Allow-Headers; # 添加新的CORS头 add_header Access-Control-Allow-Origin "*" always; # 允许所有来源 add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always; add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,Content-Type,Accept,Authorization" always; add_header Access-Control-Expose-Headers "Content-Length,Content-Range" always; } ``` - `proxy_hide_header`用于移除后端可能冲突的响应头[^4] - `always`参数确保即使响应码为4xx/5xx也添加头[^1] #### 4. **安全增强建议(可选)** ```nginx add_header Access-Control-Allow-Credentials "true"; # 允许携带凭证(如Cookie) add_header Access-Control-Allow-Origin "https://your-domain.com"; # 生产环境指定具体域名 add_header Cache-Control "no-store"; # 防止缓存敏感CORS响应 ``` #### 5. **完整配置示例** ```nginx server { listen 80; server_name api-gateway.example.com; location /api/ { if ($request_method = OPTIONS) { add_header Access-Control-Allow-Origin "https://client-app.example.com"; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; add_header Access-Control-Allow-Headers "Authorization, Content-Type"; add_header Access-Control-Max-Age 3600; return 204; } proxy_pass http://backend-server:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_hide_header 'Access-Control-Allow-Origin'; proxy_hide_header 'Access-Control-Allow-Methods'; add_header Access-Control-Allow-Origin "https://client-app.example.com" always; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always; add_header Access-Control-Allow-Headers "Authorization, Content-Type" always; add_header Access-Control-Expose-Headers "X-Total-Count" always; } } ``` ### 验证配置 1. 检查语法:`nginx -t` 2. 重载配置:`nginx -s reload` 3. 测试请求: ```bash curl -I -X OPTIONS http://api-gateway.example.com/api/users # 应返回包含CORS头的204响应 ``` ### 关键点说明 - **反向代理优势**:无需修改后端代码,通过中间层统一处理跨域问题[^3] - **头信息覆盖**:必须先用`proxy_hide_header`清除后端可能设置的CORS- **生产环境安全**: - 替换`*`为具体的允许域名 - 限制允许的HTTP方法和头信息 - 考虑添加速率限制防止滥用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乐享技术

每一个打赏,都是对我最大的鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值