1. 跨域
1.1 同源策略
同源策略(Same-Origin Policy)是浏览器的一种安全机制,它限制了不同源之间的资源共享。两个 URL 被认为是同源的,必须满足以下三个条件:
- 协议相同 (如 http或https)
- 域名相同
- 端口相同
例如:
- 同源:
- http://example.com:8080和- http://example.com:8080
 
- 跨域:
- http://example.com:8080和- http://example.com:3000(端口不同)
- http://example.com和- https://example.com(协议不同)
- http://example.com和- http://api.example.com(域名不同)
 
1.2 跨域资源共享(CORS)
CORS 是一种机制,通过设置特定的 HTTP 响应头,允许浏览器访问跨域资源。CORS 头主要包括:
- **Access-Control-Allow-Origin**:指定允许访问的源。
- **Access-Control-Allow-Methods**:指定允许的 HTTP 方法(如- GET,- POST)。
- **Access-Control-Allow-Headers**:指定允许的请求头(如- Content-Type,- Authorization)。
- **Access-Control-Allow-Credentials**:是否允许携带 Cookie 或其他凭证。
- **Access-Control-Max-Age**:预检请求的缓存时间。
2. Nginx 配置跨域的场景
2.1 场景 1:简单跨域请求
如果前端发送的是 简单请求 (如 GET 或 POST,且没有自定义请求头),Nginx 只需要在响应中添加跨域头即可。
2.2 场景 2:复杂跨域请求
如果前端发送的是 复杂请求 (如 POST 请求包含 Content-Type: application/json 或自定义头 Authorization 等),浏览器会先发起 预检请求(OPTIONS),询问服务器是否允许跨域。
Nginx 必须正确处理 OPTIONS 请求,并返回所有必要的跨域头。
3. Nginx 配置跨域的完整实现
3.1 基础跨域配置
基础的 Nginx 跨域配置示例:
            
            
              nginx
              
              
            
          
          server {
  listen 8081;
  server_name localhost;
  # 根目录(H5 前端文件)
  root /usr/share/nginx/html/applet/dist/build/h5/;
  # 跨域配置
  location /api/ {
    # 添加跨域头
    add_header 'Access-Control-Allow-Origin' '*' always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
    add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    # 如果是预检请求 (OPTIONS),直接返回成功
    if ($request_method = 'OPTIONS') {
      add_header 'Access-Control-Allow-Origin' '*' always;
      add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
      add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With';
      add_header 'Access-Control-Max-Age' 1800;
      add_header 'Content-Length' 0;
      add_header 'Content-Type' 'text/plain';
      return 204;
    }
    # 反向代理到后端服务
    proxy_pass url; # 替换为后端服务地址
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}3.2 配置解析
- Access-Control-Allow-Origin:允许的跨域来源。如果后端需要支持多个来源,可以动态设置该值;或者使用- *表示允许所有来源。
- Access-Control-Allow-Methods:声明支持的 HTTP 方法。
- Access-Control-Allow-Headers:声明允许的自定义请求头。如果前端发送了- Authorization或其他自定义头,必须在这里明确声明。
- Access-Control-Max-Age:指定预检请求的缓存时间,单位为秒(如- 1800表示缓存 30 分钟)。
- if ($request_method = 'OPTIONS'):单独处理预检请求,直接返回- 204,避免请求被转发到后端。
- 在 if判断中直接返回响应(如return 204)的情况下,add_header** 需要在同一个if块内声明**,否则不会被应用到响应中。这里主要是nginx的响应流程和作用域特性。
3.3 动态配置跨域来源
如果后端需要允许多个特定来源,可以通过 $http_origin 动态设置 Access-Control-Allow-Origin:
            
            
              nginx
              
              
            
          
          location /api/ {
  # 动态设置跨域来源
  set $cors "";
  if ($http_origin ~* (http://ip:port|http://example.com)) {
    set $cors $http_origin;
  }
  add_header 'Access-Control-Allow-Origin' $cors always;
  add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
  add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always;
  add_header 'Access-Control-Allow-Credentials' 'true' always;
  # 如果是预检请求 (OPTIONS),直接返回成功
  if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Allow-Origin' $cors always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
    add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With';
    add_header 'Access-Control-Max-Age' 1800;
    add_header 'Content-Length' 0;
    add_header 'Content-Type' 'text/plain';
    return 204;
  }
  proxy_pass bakcendurl;
}4. 验证跨域配置是否生效
4.1 使用 curl 验证
预检请求
运行以下命令,检查 OPTIONS 请求的响应头是否包含正确的跨域头:
            
            
              bash
              
              
            
          
          curl -X OPTIONS http://localhost:8081/api/test-endpoint \
-H "Origin: yoururl" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: Content-Type, Authorization" -I实际请求
运行以下命令,检查实际请求的跨域头:
            
            
              nginx
              
              
            
          
          curl -X POST http://localhost:8081/api/test-endpoint \
-H "Origin: yoururl" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{"key":"value"}' -I将Origin的值替换即可。
5. 常见问题及解决方法
5.1 No 'Access-Control-Allow-Origin' header is present on the requested resource
- 原因 :后端未返回 Access-Control-Allow-Origin。
- 解决:检查 Nginx 或后端服务是否返回了正确的跨域头。
5.2 Request header field <header_name> is not allowed by Access-Control-Allow-Headers
- 原因:前端发送了未被允许的自定义请求头。
- 解决 :在 Access-Control-Allow-Headers中添加该头(如Authorization,channel等)。
5.3 OPTIONS 请求返回 404 或 405
- 原因:Nginx 或后端未正确处理 OPTIONS 请求。
- 解决 :在 Nginx 配置中使用 if ($request_method = 'OPTIONS')单独处理预检请求。
6. 注意事项
(1) 不建议长期使用通配符 *
- 如果前端需要发送 Authorization或Cookie,不能使用通配符*,需要指定具体的跨域来源:
            
            
              nginx
              
              
            
          
          add_header 'Access-Control-Allow-Origin' 'http://ip:port' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;(2) 确保前端请求头与后端配置匹配
- 如果前端发送了自定义头(如 channel),后端的Access-Control-Allow-Headers必须包含这些头。
(3) 确保后端不会覆盖 Nginx 的跨域头
- 如果后端服务也返回了跨域头,可能会覆盖 Nginx 的配置。可以通过 proxy_hide_header移除后端返回的头:
            
            
              nginx
              
              
            
          
          proxy_hide_header Access-Control-Allow-Origin;
proxy_hide_header Access-Control-Allow-Methods;
proxy_hide_header Access-Control-Allow-Headers;6. 总结
- CORS 的核心 在于配置正确的跨域头(Access-Control-Allow-*)。
- Nginx 配置跨域的关键点 :
- 处理预检请求(OPTIONS)。
- 添加必要的跨域头(Access-Control-Allow-Origin,Access-Control-Allow-Headers等)。
- 确保跨域头在所有响应中生效(使用 always参数)。
 
- 使用工具(如 curl或浏览器开发者工具)验证跨域配置是否正确。
Ending