跨域问题

介绍了跨域相关知识

1. 什么是跨域?

  • 简单来说:不同域名/端口/协议之间的请求被浏览器阻止了,这就是跨域问题。
  • 必须同源浏览器才允许互相访问数据,跨域的参照物是当前网页的域名
条件 示例
协议 http://https://
域名 example.com
端口 :80, :3000
比较项 页面名片 (A) 请求名片 (B) 结果
协议 https://example.com http://example.com 跨域 (协议不同)
域名 https://api.example.com https://web.example.com 跨域 (子域名不同)
端口 https://example.com(https://me.com/):8080 https://example.com:9000 跨域 (端口不同)
全匹配 https://example.com https://example.com/data 同源 (安全通过)

2. 为什么会有跨域限制?

跨域(CORS)是浏览器的一种保护机制

  • 假设你登录了微博 weibo.com,浏览器存了你的登录状态(Cookie)。
  • 此时你打开了一个看小说的网页 novel.com
  • 如果没跨域限制:novel.com 里的 JS 脚本可以直接写一段代码 fetch('https://weibo.com/delete-post')
  • 后果: 浏览器会带着你的 Cookie 发出请求,微博服务器以为是你本人想删贴,于是操作成功。

浏览器设立跨域限制的逻辑是:“除非 weibo.com 明确告诉我它信任 novel.com,否则我不允许 novel.com 的脚本去碰 weibo.com 的数据。”

3. JS 发送请求时的过程

1.域名一致(同源)

  • 浏览器的判断: 比较发现“协议+域名+端口”完全一致。
  • 行为: 直接发送请求。 不会有任何额外的询问,就像你在家里从厨房走到卧室拿东西一样自然。

2.情况二:域名不一致(跨域)

这时浏览器会根据请求的内容,决定是先斩后奏还是先请示再行动

  • 简单请求 —— “先斩后奏”

请求很“简单”(比如普通的 GETPOST

  • 复杂请求 —— “先请示再行动”

请求比较“高级”(比如 PUTDELETE,或者你在 Header 里加了 Authorization 令牌)

4.跨域的常见解决方案

  • CORS

    原理: 后端设置响应头,告诉浏览器:“我允许这个网站访问我的资源。

    Spring MVC设置允许跨域

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    @Configuration
    @RequiredArgsConstructor
    public class CorsConfig implements WebMvcConfigurer {
    
        private final CorsProperties corsProperties;
    
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
                    //允许发送cookie
                    .allowCredentials(true)
                    //放行哪些域名 因为allowCredentials要发送cookie 所以必须是具体的源地址
                    .allowedOrigins(corsProperties.getAllowOrigins().toArray(new String[0]))
                    .allowedHeaders("*")
                    .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                    .exposedHeaders("*");
        }
    }
    
  • Nginx代理转发

    原理:跨域问题本质是浏览器的安全校验,因此只要绕过浏览器就好了。先将请求发给Nginx服务器,然后Nginx再将请求转发给后端,后端返回结果给Nginx服务器,Nginx再返回给前端。看上去是同源

1
2
3
4
5
6
7
8
9
    location ^~ /api {
      proxy_pass http://域名:8123;
      proxy_set_header Host $proxy_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      # 增加错误调试信息
      proxy_intercept_errors off;
    }

5.一些小细节

事实上:当你从 a.com 的网页向 b.com/api 发送 JS 请求时,浏览器会自动在 HTTP 请求头(Headers)里加上:

  • Origin字段

    • 内容: Origin: http://a.com
    • 作用: 它是专门为了 CORS(跨域资源共享) 设计的。它只包含“协议+域名+端口”,不包含具体的路径。
    • 浏览器的逻辑: “我得告诉 b.com,这行 JS 代码是 a.com 指使我运行的。b.com 你自己看着办,准不准它读你的数据。”
  • Referer 字段

    • 内容: Referer: http://a.com/pages/index.html
    • 作用: 它比 Origin 更详细,包含了具体的来源页面全路径
    • 浏览器的逻辑: “我得告诉 b.com,用户是从哪一个具体的页面跳过来的。”
最后更新于 2026-03-24