跨域 (CORS) 原理:浏览器的“尽职保镖”

🚫 那个让前端抓狂的红字报错

作为前端开发,你一定见过这个经典的报错:

Access to XMLHttpRequest at 'http://api.server.com' from origin 'http://localhost:8080' has been blocked by CORS policy

这时候你可能会想:"我就调个接口,为什么浏览器要拦着我?"

其实,这不是浏览器在故意刁难你,而是它在保护用户 。这个机制叫做同源策略 (Same-Origin Policy)


🏠 什么是"同源策略"?

1. 核心概念

浏览器有一个默认的安全规则:A 网站的 JavaScript,不能随便读取 B 网站的数据

除非 A 和 B 是"一家人"(同源)。

2. 怎样才算"一家人"?

必须同时满足以下三个条件,才算同源

  1. 协议相同 (Protocol):都是 http 或都是 https
  2. 域名相同 (Domain):都是 www.example.com
  3. 端口相同 (Port):都是 80 (或都不写)。

只要有一个不一样,就是跨域

当前页面 请求接口 结果 原因
http://a.com http://a.com/api ✅ 同源 一家人
http://a.com https://a.com/api ❌ 跨域 协议不同 (http vs https)
http://a.com http://b.com/api ❌ 跨域 域名不同
http://a.com http://a.com:8080 ❌ 跨域 端口不同 (80 vs 8080)

👮‍♂️ 为什么要有这个策略?(比喻)

想象一下:

  • 浏览器 = 你的小区 🏘️
  • 同源策略 = 小区保安 👮‍♂️
  • 恶意网站 = 推销员 🦹

如果你登录了银行网站 (bank.com),银行给你发了一张通行证 (Cookie) 存在浏览器里。

然后你不小心点开了恶意网站 (evil.com)。如果没有同源策略:

  1. evil.com 的代码悄悄向 bank.com 发送请求:"我要转账"。
  2. 浏览器发现你有 bank.com 的通行证,于是就带上通行证发请求了。
  3. 银行一看通行证是真的,钱就被转走了! 💸

但是,因为有同源策略 (保安)

保安发现:"哎?你是 evil.com (推销员),你想去 bank.com (金库) 拿东西?不行!你的工牌对不上!"

于是请求被拦截,你的钱保住了。


🔓 怎么解决跨域?(三种常见方案)

虽然同源策略是为了安全,但在开发中,我们的前端 (localhost:8080) 和后端 (api.com) 往往不在同一个域,确实需要通信。怎么办?

1. CORS (官方推荐:发通行证) ✅

CORS 全称是 Cross-Origin Resource Sharing (跨域资源共享)。

原理很简单:后端服务器告诉浏览器:"在这个名单里的人,可以放行。"

流程图解:

🖥️ 后端 (api.com) 🌍 浏览器 (localhost) 🖥️ 后端 (api.com) 🌍 浏览器 (localhost) 准备发送复杂请求 (如带Token) 预检请求 (Preflight) 查白名单:允许!✅ OPTIONS /api (有人在吗?我能进吗?) 200 OK (Header: Allow localhost) GET /api (真正的请求) {data: ...} (拿到数据)

流程:
  1. 浏览器 :我想去 api.com 拿数据,但我来自 localhost:8080,行吗?
  2. 浏览器 (如果是复杂请求,先发一个 OPTIONS 预检请求):有人在吗?我能进吗?
  3. 后端服务器 :收到,我查一下白名单... 好的,允许 localhost:8080 访问!(返回响应头 Access-Control-Allow-Origin: http://localhost:8080)
  4. 浏览器 :看到后端点头了,保安放行,数据拿到。

后端代码示例 (Node.js/Express):

javascript 复制代码
app.use((req, res, next) => {
  // 允许 localhost:8080 访问
  res.header('Access-Control-Allow-Origin', 'http://localhost:8080');
  // 允许的方法
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  next();
});

2. 代理 (Proxy) (欺骗保安) 🎭

同源策略只限制浏览器,不限制服务器! 服务器和服务器之间通信是自由的。

我们可以找一个中间人 (代理服务器),让他去帮我们拿数据。

原理:
  1. 前端 (localhost:8080) 不直接找后端,而是找 本地代理 (localhost:8080/api)。
  2. 保安 一看:你找你自己家的人,同源,放行!
  3. 本地代理 悄悄去 后端 (api.com) 把数据拿回来。
  4. 本地代理 再把数据给 前端

Vue 配置示例 (vue.config.js):

javascript 复制代码
module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://api.com', // 真正的后端地址
        changeOrigin: true,       // 告诉后端:我是从 api.com 来的 (伪装)
        pathRewrite: { '^/api': '' }
      }
    }
  }
}

3. Nginx 反向代理 (生产环境常用) 🔄

原理和上面一样,只不过是在部署时,用 Nginx 做这个"中间人"。

Nginx 配置:

nginx 复制代码
server {
    listen 80;
    server_name my-website.com;

    # 前端文件
    location / {
        root /usr/share/nginx/html;
    }

    # 接口转发
    location /api/ {
        proxy_pass http://api-server.com/; # 转发给后端
    }
}

这样对浏览器来说,前端和接口都在 my-website.com 下,完美同源


🧪 进阶知识:面试必问细节

1. 简单请求 vs 复杂请求 (为什么会有 OPTIONS?) 🕵️

有时候你会发现浏览器自动 多发了一个 OPTIONS 请求,这叫预检请求 (Preflight)

  • 简单请求 (Simple Request) :直接发,不预检。
    • 方法是 GET, HEAD, POST
    • Header 只有常见的 Accept, Content-Type 等。
    • Content-Type 只能是 text/plain, multipart/form-data, application/x-www-form-urlencoded
  • 复杂请求 (Preflighted Request) :先发 OPTIONS 问路。
    • 用了 PUT, DELETE 方法。
    • 发送了 JSON 数据 (Content-Type: application/json)。
    • 加了自定义 Header (如 Authorization, Token)。

结论 :大部分现代前后端分离应用(发 JSON、带 Token)都是复杂请求 ,所以看到 OPTIONS 不要慌,那是浏览器在礼貌问路。

默认情况下,跨域请求不带 Cookie。如果你需要登录态,必须两边都配合:

  1. 前端 (axios) :开启 withCredentials: true
  2. 后端
    • Access-Control-Allow-Credentials: true (允许带证件)。
    • Access-Control-Allow-Origin 不能*,必须写死具体域名 (如 http://localhost:8080)。

3. JSONP (时代的眼泪) 👴

在 CORS 还没普及的年代,前辈们发现 <script src="..."> 标签不受同源策略限制(你可以引用百度的 JS)。

于是利用 <script> 偷运数据,这就是 JSONP。现在除了老旧系统,基本不用了。


🧠 总结

  1. 跨域 是因为浏览器的同源策略,为了保护你的安全。
  2. 同源 = 协议域名端口 三者都一样。
  3. 解决办法
    • CORS:后端加响应头,发"通行证"。(最常用)
    • Proxy:前端/Nginx 做代理,让"中间人"去拿数据。(开发/生产环境常用)
相关推荐
天荒地老笑话么12 小时前
静态 IP 规划:掩码/网关/DNS 的正确组合
网络·网络协议·tcp/ip·网络安全
大方子1 天前
【PolarCTF】rce1
网络安全·polarctf
枷锁—sha1 天前
Burp Suite 抓包全流程与 Xray 联动自动挖洞指南
网络·安全·网络安全
聚铭网络1 天前
聚铭网络再度入选2026年度扬州市网络和数据安全服务资源池单位
网络安全
darkb1rd1 天前
八、PHP SAPI与运行环境差异
开发语言·网络安全·php·webshell
世界尽头与你2 天前
(修复方案)基础目录枚举漏洞
安全·网络安全·渗透测试
枷锁—sha2 天前
【SRC】SQL注入快速判定与应对策略(一)
网络·数据库·sql·安全·网络安全·系统安全
liann1193 天前
3.1_网络——基础
网络·安全·web安全·http·网络安全
ESBK20253 天前
第四届移动互联网、云计算与信息安全国际会议(MICCIS 2026)二轮征稿启动,诚邀全球学者共赴学术盛宴
大数据·网络·物联网·网络安全·云计算·密码学·信息与通信
旺仔Sec3 天前
一文带你看懂免费开源 WAF 天花板!雷池 (SafeLine) 部署与实战全解析
web安全·网络安全·开源·waf