​​浏览器如何拦截跨域请求?——像小区保安一样层层设卡​

你可能好奇:​​“浏览器是怎么发现跨域请求并拦截的?它又凭什么说‘这个请求不能通过’?”​
其实,浏览器的拦截机制就像小区门口的保安,会严格检查每一个“进出请求”,一旦发现不符合规则(跨域且没通行证),就会立刻拦下。下面我们分步骤拆解这个过程,用生活化的比喻帮你彻底理解。


​一、浏览器的“保安岗哨”:同源策略(Same-Origin Policy)​

浏览器的核心安全机制叫​​同源策略​​,它规定:

​只有协议、域名、端口完全相同的网站(即“同源”),才能直接互相访问数据。​
如果违反了这一规则(比如你的网页是 https://奶茶店.com,却想直接读取 https://咖啡工厂.com 的数据),浏览器就会触发拦截。

​举个栗子🌰​​:

  • 同源:https://奶茶店.com/page1https://奶茶店.com/page2(协议、域名、端口都一样)。
  • 跨域:https://奶茶店.com 想访问 https://咖啡工厂.com/api/data(域名不同),或者 http://奶茶店.com 想访问 https://奶茶店.com/api/data(协议不同)。

​二、拦截的“分步流程”:从请求发出到被拦下​

当你的前端代码(比如JavaScript)发起一个跨域请求时,浏览器会像保安一样层层检查,最终决定是否放行。具体流程如下:


​1️⃣ 第一步:浏览器发现请求是跨域的​

当你执行类似 fetch('https://咖啡工厂.com/api/data') 的代码时,浏览器会先解析目标URL(https://咖啡工厂.com/api/data),然后对比当前网页的地址(比如 https://奶茶店.com):

  • ​如果协议、域名、端口有一个不同​​ → 判定为跨域请求。
  • ​如果是同源请求​​ → 直接放行,不会触发CORS检查(因为同源策略允许)。

​此时浏览器心里想​​:

“哎?这个请求的目标地址和当前网页不是一个地方的!得先看看对方(服务器)有没有给我开通行证(CORS头部)。”


​2️⃣ 第二步:浏览器先发一个“试探请求”(如果是非简单请求)​

根据请求的类型(简单请求 or 非简单请求),浏览器的行为会有所不同:

​情况A:简单请求(GET/POST/HEAD + 简单头部)​
  • 浏览器​​直接发送真实请求​​到服务器(比如 GET https://咖啡工厂.com/api/data),但会在请求头里偷偷塞一个 Origin: https://奶茶店.com(告诉服务器:“我是从奶茶店来的”)。
  • 服务器收到请求后,如果支持CORS,会在响应头里返回 Access-Control-Allow-Origin: https://奶茶店.com(盖章:“允许奶茶店访问”)。
  • ​如果服务器没返回CORS头部​​ → 浏览器直接拦截响应,哪怕服务器已经返回了数据!
​情况B:非简单请求(PUT/DELETE/带自定义头部等)​
  • 浏览器​​不会直接发真实请求​​,而是先发一个 OPTIONS 请求(叫“预检请求”),问服务器:

    “我想发一个 PUT /api/data 请求,还带了 X-Custom-Header: xxx,你允许吗?”

  • 服务器需要回复:
    • 是否允许这个方法(Access-Control-Allow-Methods: PUT);
    • 是否允许这些头部(Access-Control-Allow-Headers: X-Custom-Header);
    • 是否允许这个来源(Access-Control-Allow-Origin: https://奶茶店.com)。
  • ​如果服务器没通过预检​​ → 浏览器直接拦截,不会发真实请求!
  • ​如果服务器通过了预检​​ → 浏览器才会发真正的 PUT 请求。

​关键点​​:
无论是简单请求还是非简单请求,​​只要服务器没返回正确的CORS头部​​,浏览器就会拦截响应或请求!


​3️⃣ 第三步:浏览器检查响应头是否有“通行证”​

如果服务器返回了数据,浏览器会检查响应头里有没有以下关键字段:

  • Access-Control-Allow-Origin: https://奶茶店.com(或 * 表示允许所有域名)。
  • 其他可能的CORS头部(如 Access-Control-Allow-MethodsAccess-Control-Allow-Headers)。

​如果缺少这些头部​​ → 浏览器直接拦截数据,前端代码拿不到任何结果!
​如果头部正确​​ → 浏览器放行数据,前端代码可以正常使用。


​三、拦截的表现:前端代码“悄无声息”地失败​

当浏览器拦截跨域请求时,​​前端代码不会收到任何数据​​,但也不会直接报“网络错误”(因为请求可能已经发到服务器了,只是浏览器不让用结果)。你会在浏览器的开发者工具(F12→Console)里看到类似这样的报错:

Access to fetch at 'https://咖啡工厂.com/api/data' from origin 'https://奶茶店.com' 
has been blocked by CORS policy: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.

​翻译成人话​​:

“浏览器发现你跨域访问了 https://咖啡工厂.com 的数据,但对方没给你开通行证(响应头里没有 Access-Control-Allow-Origin),所以直接没收了数据,你啥也拿不到!”


​四、对比:为什么Postman/curl能拿到数据,但浏览器不行?​

很多人会疑惑:

“我用Postman或者命令行工具(如curl)访问同一个API,明明能拿到数据,为什么浏览器就不行?”

​原因很简单​​:

  • ​Postman/curl不受同源策略限制​​:它们是“直接访问”服务器的工具,没有浏览器的安全限制,所以不管服务器有没有CORS头部,都能拿到数据。
  • ​浏览器有“保安”(同源策略)​​:浏览器必须严格遵守CORS规则,如果没有通行证,即使服务器返回了数据,也会被强行拦截。

​类比​​:

  • Postman/curl就像快递员直接进工厂拿货,工厂不管是谁来拿,只要货存在就给。
  • 浏览器就像顾客去超市买东西,必须出示会员卡(同源)或者临时通行证(CORS头部),否则保安(浏览器)会拦住你。

​五、总结:浏览器拦截跨域请求的“核心逻辑”​

  1. ​先判断是否跨域​​:对比协议、域名、端口,不同就是跨域。
  2. ​如果是非简单请求,先发 OPTIONS 预检请求​​,问服务器是否允许。
  3. ​服务器响应后,检查响应头有没有 Access-Control-Allow-Origin​:
    • 有且匹配当前域名 → 放行数据。
    • 没有或匹配失败 → 拦截数据。
  4. ​前端代码只能拿到被放行的数据​​,被拦截的请求对开发者透明(只能看到报错)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值