Nginx配置允许跨域

适用场景:Web服务器配置、API接口开发、静态资源托管

跨域(CORS)基础概念

什么是跨域?

浏览器出于安全考虑,禁止网页从一个域名(如 https://a.com)请求另一个域名(如 https://b.com)的资源。CORS(跨域资源共享)通过HTTP头字段允许服务器声明允许的源,解决跨域问题。

Nginx 配置方法

方法一:全局允许所有域名跨域

适用场景:开发环境快速测试(不推荐生产环境使用)。

配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
listen 80;
server_name example.com;

location / {
# 允许所有域名跨域(* 表示通配符)
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,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;

# 处理预检请求(OPTIONS)
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;
}

# 后端代理配置
proxy_pass http://backend;
}
}

配置说明

  • Access-Control-Allow-Origin:允许跨域的域名,* 表示允许所有域名。
  • Access-Control-Allow-Methods:允许的 HTTP 方法(如 GETPOST 等)。
  • Access-Control-Allow-Headers:允许的请求头。
  • Access-Control-Expose-Headers:允许客户端访问的响应头。
  • Access-Control-Max-Age:预检请求的缓存时间(单位:秒)。
  • OPTIONS 请求:用于处理浏览器的预检请求(Preflight Request)。

方法二:允许特定域名跨域

适用场景:生产环境安全配置。

配置示例

如果只想允许特定域名跨域,可以将 Access-Control-Allow-Origin 设置为具体的域名:

1
2
3
4
5
6
7
8
9
10
11
server {
listen 80;
server_name example.com;

location / {
# 允许特定域名(如 https://client.example.com)
add_header 'Access-Control-Allow-Origin' 'https://client.example.com' always;

# 其他配置与方法一相同...
}
}

方法三:允许多个域名跨域

适用场景:需要支持多个可信域名。

配置示例

Nginx 原生不支持直接配置多个域名,但可以通过变量和条件判断实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 定义允许的域名列表
map $http_origin $cors_origin {
default ''; # 默认拒绝
"~^https://client1\.example\.com$" $http_origin;
"~^https://client2\.example\.com$" $http_origin;
}

server {
listen 80;
server_name example.com;

location / {
# 动态设置允许的域名
add_header 'Access-Control-Allow-Origin' $cors_origin always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;

# 处理预检请求(OPTIONS)
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;
}

# 后端代理配置
proxy_pass http://backend;
}
}

方法四:静态文件跨域配置

适用场景:直接通过Nginx提供静态资源(如图片、文件)

配置示例

如果 Nginx 直接提供静态文件服务,可以在 location 块中添加跨域头:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
server {
listen 80;
server_name static.example.com;

location /static/ {
# 允许所有域名跨域(* 表示通配符)
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,If-Modified-Since,Cache-Control,Content-Type,Range' always;

# 处理 OPTIONS 预检请求
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;
}

# 静态文件路径
alias /path/to/static/files/;
}
}

注意事项

  1. 安全建议
    • 避免生产环境使用 *:可能导致安全漏洞,建议指定具体域名。
    • HTTPS优先:跨域源建议使用HTTPS协议。
  2. 缓存问题
    • 浏览器可能缓存预检请求结果,修改配置后需清理浏览器缓存。
  3. 代理配置兼容性
    • 如果后端服务(如Node.js)已配置CORS,需确保Nginx与后端配置不冲突。
  4. 版本兼容性:Nginx 1.19+(支持 always 参数)

测试与验证

配置完成后,重启 Nginx 并测试跨域是否生效:

1
2
sudo nginx -t  # 测试配置文件语法
sudo systemctl restart nginx # 重启 Nginx

使用浏览器开发者工具或 curl 命令检查响应头:

1
2
curl -I -H "Origin: https://client.example.com" http://example.com/api
# 查看响应头是否包含 Access-Control-Allow-Origin

确保响应头中包含 Access-Control-Allow-Origin 等相关字段。

扩展配置技巧

技巧1:动态设置CORS头

根据请求来源动态返回允许的域名:

1
2
3
4
5
6
7
8
9
10
# 在 server 块中定义变量
map $http_origin $allowed_origin {
default '';
"~^(https?://)?.+\.example\.com$" $http_origin;
}

location /api {
add_header 'Access-Control-Allow-Origin' $allowed_origin always;
# 其他配置...
}

技巧2:限制HTTP方法

仅允许安全的方法(如GET/POST):

1
add_header 'Access-Control-Allow-Methods' 'GET, POST' always;