Nginx — 跨域问题演示以及解决方法

[复制链接]
发表于 2026-10-5 20:12:24 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

前后端分离之后,跨域几乎是必过的一关。浏览器报的那串 "has been blocked by CORS policy" 往往让新手以为后端挂了,其实数据 200 已经回来了,是浏览器拦下了响应。这篇用一台装了 nginx 的机器现场复现跨域报错,再给出 add_header 的完整解法,顺带把同源策略、Access-Control-Allow-Origin、Access-Control-Allow-Methods 三个概念一次讲透。

一、成因与目标

1. 为什么要跨域

同源策略限制:协议、域名、端口号三者全同才算同源。当 Web 应用要和不同源的服务器交换数据、或嵌入异域的视频图片时,就涉及跨域。

2. 跨域的三个真实用途

  • 数据共享与交互:电商网站要拿供应商服务器的实时库存,两边域名天生不同。
  • 多平台协作:不同团队/公司维护不同域名与部署环境,第三方应用要把分享请求传给对方平台。
  • 资源复用:字体库、JS 库、图片库放在专门的 CDN 域名上,网站引用它们同样是跨域。

二、什么是同源

两个 URL 的协议、域名、端口号相同即为同源。

同源示例:

http://www.example.com/index.html
http://www.example.com/page.html

两处都是 HTTP、域名 www.example.com、端口用 HTTP 默认 80(URL 里没写就默认 80)。

不同源示例:

https://www.example.com/index.html   # 协议是 HTTPS
http://api.example.com/index.html    # 域名不同
http://www.example.com:8080/...      # 端口 8080 ≠ 80

同源策略是浏览器安全的基石:它限制不同源文档或脚本之间的交互,防止恶意网站通过脚本摸到别的站点的敏感信息。

三、实验准备

一台装好 nginx 的机器,准备两件事:

  • /opt/nginx/a.html:页面里放一个按钮,点击后 $.get('http://192.168.72.130:8888/getUser');
  • 两个监听不同端口的 server,一个 9999 出页面,一个 8888 出数据。

1. 页面文件

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>跨域问题演示</title>
  <script src="jquery.js"></script>
</head>
<body>
  <button id="btn">请求数据</button>
  <script>
  $(function(){
    $("#btn").click(function(){
      $.get('http://192.168.72.130:8888/getUser', function(data){
        alert(JSON.stringify(data));
      });
    });
  });
  </script>
</body>
</html>

坑点先讲:jquery.js 必须提前放在和 a.html 同一个目录,否则控制台直接抛 Uncaught ReferenceError: $ is not defined。这个是引用路径问题,和跨域无关,却经常掩盖真正的跨域报错。

2. 两个不同源的 server

server {
    listen 9999;
    server_name localhost;
    gzip on;
    root /opt/nginx;
    location / {
        index a.html;
    }
}

server {
    listen 8888;
    server_name localhost;
    gzip on;
    root /opt/nginx;
    location /getUser {
        default_type application/json;
        return 200 '{"id":"123","name":"小明","age":"18"}';
    }
}

访问 http://192.168.72.130:8888/getUser 能拿到 JSON,访问 http://192.168.72.130:9999/ 能出页面,但页面按钮点了没反应——跨域就在这一步发生了。

四、报错现象分析

浏览器控制台会给出这段:

Access to XMLHttpRequest at 'http://192.168.72.130:8888/getUser'
from origin 'http://192.168.72.130:9999' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.

拆成两条逻辑:

  1. 同源策略与 CORS:请求源是 9999,目标资源源是 8888,端口不同就是跨域,浏览器按同源策略拦。
  2. Access-Control-Allow-Origin 头缺失:浏览器检查响应头里有没有这个字段,没有就拒绝把响应交给脚本——哪怕服务端已经 200 返回了数据。

所以第二行 GET net::ERR_FAILED 200 (OK) 看着矛盾:200 是服务器说"我处理完了",ERR_FAILED 是浏览器说"我不给你用"。这也解释了为什么很多人 curl 接口明明通、页面却取不到数据。

五、解决

1. 方案说明

用 add_header 指令补响应头。它的语法与默认值:

指令语法默认值可放位置
add_headeradd_header name value ...—http、server、location

这里要补两个头:

  • Access-Control-Allow-Origin:允许跨域访问的源地址,可配多个(逗号分隔),也可用 * 代表所有源。
  • Access-Control-Allow-Methods:允许的请求方式,GET/POST/PUT/DELETE 等,多个逗号分隔,按需开放不要图省事全给。

2. 配置

server {
    listen 8888;
    server_name localhost;
    gzip on;
    root /opt/nginx;

    location /getUser {
        # 允许 http://192.168.72.130:9999 这个源访问
        add_header Access-Control-Allow-Origin http://192.168.72.130:9999;
        # 允许的请求方法
        add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE;
        default_type application/json;
        return 200 '{"id":"123","name":"小明","age":"18"}';
    }
}

把 Origin 写死成具体源,比 * 安全得多:生产环境用 * 意味着任何站点都能读你的接口,配合 Cookie 时甚至会直接违反浏览器规范。

3. 验证

sudo nginx -t
sudo systemctl reload nginx

改完先做语法检查再 reload,别一上来就 restart。回车后回到 http://192.168.72.130:9999/ 再点按钮,弹出 JSON 即跨域打通。

六、三个补充场景

  • 自定义请求头或 application/json:会触发预检 OPTIONS,需要在 location 里补 if ($request_method = OPTIONS) { return 204; } 并回 Access-Control-Allow-Headers。
  • 带 Cookie:必须把 Access-Control-Allow-Credentials 设为 true,同时 Origin 不能是 *,前端请求要带 credentials。
  • 纯静态资源跨域引用:img、script、link 这类标签不受 CORS 限制,只有 XMLHttpRequest / fetch 才受同源策略管。

跨域问题的本质只有一句:服务端给不给"你准予访问"这个头。明白了这点,报错信息就不再神秘——看它指哪个头缺失,补上就好。

qidao123.com企服评测-应用市场 编辑提示

本文按同源的定义与四个非同源示例、CORS 的三种业务用途、双 server 不同端口复现环境、a.html 与 jquery.js 同目录的引用要点、Access to XMLHttpRequest 报错的逐段拆解、add_header 指令的语法默认值与 Access-Control-Allow-Origin / Methods 两个头、以及预检 OPTIONS 与带 Cookie 场景的差异,重排成"现象—原因—解决—扩展"的闭环。文中 IP、端口、路径与示例 JSON 均为实验示意值,配置项取自 nginx 官方文档,请以实际环境为准;跨域头在生产环境建议按具体源白名单配置并在自有服务上验证。

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表