跨域是服务器拒绝请求还是浏览器去拒绝的请求?

这是一个非常好的问题!简单来说:跨域限制是浏览器主动实施的,服务器可以参与控制这个过程,但最终是浏览器决定是否拒绝请求。

让我详细解释一下:

1. 浏览器是执行者

  • 跨域请求(CORS - Cross-Origin Resource Sharing)限制是浏览器的安全策略
  • 当你从一个源(如 https://example.com)的网页中向另一个源(如 https://api.other.com)发送AJAX/fetch请求时,浏览器会自动:
    1. 检查请求是否是"简单请求"还是"非简单请求"
    2. 对于非简单请求,会先发送一个预检请求(OPTIONS请求)
    3. 根据服务器返回的CORS头部决定是否允许实际请求

2. 服务器的角色

服务器通过响应头告诉浏览器:

  • Access-Control-Allow-Origin:允许哪些源访问
  • Access-Control-Allow-Methods:允许哪些HTTP方法
  • Access-Control-Allow-Headers:允许哪些请求头
  • Access-Control-Allow-Credentials:是否允许发送凭据(如cookies)

3. 拒绝请求的场景

情况A:浏览器直接拒绝(没有CORS配置时)

javascript 复制代码
// 假设当前页面是 https://example.com
fetch('https://api.other.com/data')  // 不同域
  .then(...)
// 浏览器会直接报错:Cross-Origin Request Blocked
// 请求甚至没有到达 api.other.com

情况B:服务器拒绝,浏览器执行拒绝

javascript 复制代码
// 服务器返回的响应头:
// Access-Control-Allow-Origin: https://allowed.com
// 而当前源是 https://example.com
// 浏览器检查后发现不被允许,拒绝访问响应数据

4. 例外情况

  • 非浏览器环境:Node.js、Postman、curl等工具没有跨域限制
  • 服务端到服务端:服务器之间的请求不受CORS限制
  • 某些HTML标签<img><script><link>等可以跨域加载资源

关键要点

  • 浏览器主动实施:跨域是浏览器的安全策略
  • 服务器被动响应:服务器通过响应头告诉浏览器自己的跨域策略
  • 协作机制:浏览器检查服务器的CORS头部后决定是否允许请求继续

这就是为什么在开发时,前端遇到跨域问题需要后端配置CORS头部,或者在开发环境中使用代理服务器来解决跨域问题。

5. 时序图说明

这是一个跨域请求的时序图,展示浏览器、前端代码和服务器之间的交互流程:

sequenceDiagram participant F as 前端代码
(https://example.com) participant B as 浏览器 participant S as 服务器
(https://api.other.com) Note over F,S: 1. 简单请求(无预检) F->>B: 发送fetch()请求
GET /api/data B->>S: 直接发送请求 S-->>B: 返回响应 + CORS头
(Access-Control-Allow-Origin) B->>B: 检查CORS头
当前源是否在允许列表中? alt CORS允许 B-->>F: 返回响应数据 else CORS拒绝 B-->>F: 抛出跨域错误
响应被浏览器屏蔽 end Note over F,S: 2. 非简单请求(有预检) F->>B: 发送fetch()请求
PUT /api/data + 自定义头 B->>S: 发送OPTIONS预检请求 S-->>B: 返回预检响应
包含CORS策略头 B->>B: 检查预检响应 alt 预检通过 B->>S: 发送实际PUT请求 S-->>B: 返回实际响应 + CORS头 B-->>F: 返回数据 else 预检拒绝 B-->>F: 直接报错
实际请求不会发送 end

时序流程说明:

第一阶段:前端代码发起请求

  1. 前端JavaScript调用fetch()XMLHttpRequest
  2. 浏览器接收到请求指令

第二阶段:浏览器判断请求类型

bash 复制代码
简单请求条件(同时满足):
- 方法:GET、POST、HEAD
- 头部:仅限安全头部(Accept、Accept-Language等)
- Content-Type:text/plain、application/x-www-form-urlencoded、multipart/form-data

第三阶段:分叉处理

A. 简单请求路径:

  • 浏览器直接发送请求到服务器
  • 服务器返回响应和CORS头部
  • 浏览器检查CORS头部,决定是否将响应给前端代码

B. 非简单请求路径(需要预检):

diff 复制代码
触发预检的情况:
- 方法:PUT、DELETE、PATCH等
- 自定义头部:X-Custom-Header等
- Content-Type:application/json等
  1. 浏览器先发送OPTIONS预检请求
  2. 服务器返回CORS策略
  3. 关键决策点 :浏览器检查策略
    • 通过 → 发送实际请求
    • 拒绝 → 直接报错,不发送实际请求

第四阶段:最终结果

  • 成功 :数据传递给前端代码的then()onload
  • 失败 :触发catch()onerror,控制台显示跨域错误

关键决策点时序:

graph TD A[前端发起请求] --> B{浏览器判断
简单请求?} B -->|是| C[直接发送请求] B -->|否| D[发送OPTIONS预检] D --> E{服务器返回
CORS策略} E -->|允许| F[发送实际请求] E -->|拒绝| G[直接报错] C --> H[服务器返回响应] F --> H H --> I{浏览器检查
CORS头} I -->|源允许| J[传递数据给前端] I -->|源拒绝| K[屏蔽响应并报错]

实际报错示例时间点:

  • 预检阶段失败:服务器未返回正确的OPTIONS响应
  • 响应阶段失败Access-Control-Allow-Origin不匹配当前源
  • 凭证请求失败 :设置了credentials: 'include'但服务器未返回Access-Control-Allow-Credentials: true

这个时序图清晰地展示了跨域限制是浏览器主动实施的过程,服务器只是被动地响应浏览器的询问(通过CORS头部)。

相关推荐
华玥作者2 小时前
[特殊字符] VitePress 对接 Algolia AI 问答(DocSearch + AI Search)完整实战(下)
前端·人工智能·ai
Mr Xu_2 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js
前端摸鱼匠2 小时前
Vue 3 的toRefs保持响应性:讲解toRefs在解构响应式对象时的作用
前端·javascript·vue.js·前端框架·ecmascript
lang201509283 小时前
JSR-340 :高性能Web开发新标准
java·前端·servlet
好家伙VCC4 小时前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
未来之窗软件服务4 小时前
未来之窗昭和仙君(六十五)Vue与跨地区多部门开发—东方仙盟练气
前端·javascript·vue.js·仙盟创梦ide·东方仙盟·昭和仙君
嘿起屁儿整4 小时前
面试点(网络层面)
前端·网络
VT.馒头4 小时前
【力扣】2721. 并行执行异步函数
前端·javascript·算法·leetcode·typescript
phltxy5 小时前
Vue 核心特性实战指南:指令、样式绑定、计算属性与侦听器
前端·javascript·vue.js
Byron07076 小时前
Vue 中使用 Tiptap 富文本编辑器的完整指南
前端·javascript·vue.js