浏览器访问跨域

文章目录

发现问题

在Web应用开发过程中,前端页面通过浏览器调用第三方API接口时,触发了跨域资源共享(CORS)限制,导致请求被拦截。具体报错信息如下:blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

首先使用Postman测试接口,确认接口本身正常可用。进一步研究发现,Postman作为API测试工具不受浏览器同源策略限制,而浏览器环境存在CORS安全机制。

浏览器 vs Postman 跨域行为差异原理

  1. 核心原理对比
特性 浏览器 Postman
同源策略 ✅ 强制执行 ❌ 不执行
CORS 机制 ✅ 必须遵守 ❌ 不需要
安全沙箱 ✅ 有 ❌ 无
应用场景 用户日常上网 开发者调试工具
  1. 技术层面的差异
    浏览器的安全机制:





前端应用
浏览器渲染引擎
安全检查
是否同源?
允许请求
发送 OPTIONS 预检请求
服务器返回正确

CORS 头?
允许实际请求
阻塞请求并报错

Postman 的本质:
Postman
操作系统网络接口
发送原始 HTTP 请求
接收原始 HTTP 响应
显示结果给开发者

CORS

CORS(Cross-Origin Resource Sharing,跨源资源共享) 是一种基于 HTTP 头的机制,允许服务器指定哪些源(协议+域名+端口)可以访问其资源。

javascript 复制代码
// "源" 的定义
const origin = protocol + "://" + hostname + ":" + port;

// 同源示例
const origin1 = "https://example.com:443";  // 默认端口可省略
const origin2 = "https://example.com";      // 同源

// 不同源示例
"http://example.com"    // 协议不同 (http vs https)
"https://api.example.com"  // 子域名不同
"https://example.com:8080" // 端口不同

工作流程

服务器 浏览器 客户端 服务器 浏览器 客户端 发起跨域请求 alt [简单请求] [预检请求] fetch('https://other.com/api', options) 直接发送真实请求 Origin: https://client.com 响应 + CORS 头 根据 CORS 头决定是否返回响应 OPTIONS 预检请求 Origin: https://client.com Access-Control-Request-Method: POST Access-Control-Request-Headers: X-Custom 204 No Content + CORS 头 发送真实请求 真实响应 + CORS 头 返回响应数据

响应头详解

响应头 必需/可选 作用 示例 场景
Access-Control-Allow-Origin ⭐ 必需 允许的来源 https://frontend.com 所有跨域请求
Access-Control-Allow-Methods ⭐ 预检必需 允许的HTTP方法 GET, POST, OPTIONS 预检请求(OPTIONS)响应
Access-Control-Allow-Headers ⭐ 预检必需 允许的请求头 Content-Type, Authorization 预检请求中使用了非简单头部
Access-Control-Allow-Credentials ⭐ 凭证必需 是否允许凭证 true 请求需要携带凭证(cookies、认证头)
Access-Control-Expose-Headers ✅ 可选 暴露的响应头 X-Total-Count 需要前端访问自定义响应头时
Access-Control-Max-Age ✅ 可选 预检缓存时间 86400 (缓存 24 小时) 优化性能,减少预检请求
Vary: Origin ✅ 推荐 缓存区分 Origin
  1. Access-Control-Allow-Origin
    作用: 指定允许访问资源的来源
    详细说明:

    示例:

    http 复制代码
    # 语法
    Access-Control-Allow-Origin: <origin> | *
    
    # 示例
    Access-Control-Allow-Origin: *
    Access-Control-Allow-Origin: http://localhost:3000

    浏览器行为:

    xml 复制代码
    客户端请求头:Origin: http://localhost:8080
    服务器响应头:Access-Control-Allow-Origin: http://localhost:8080
    ✓ 匹配成功,允许访问
  2. Access-Control-Allow-Methods
    作用: 允许客户端使用哪些 HTTP 方法。
    详细说明:

    • OPTIONS 必须包含,用于预检请求
    • 常用的 RESTful 方法:
      • GET:获取资源
      • POST:创建资源
      • PUT:更新资源
      • DELETE:删除资源
      • PATCH:部分更新(可选)
      • HEAD:获取头部信息(可选)

    示例:

xml 复制代码
# 语法
Access-Control-Allow-Methods: <method>[, <method>]*

# 示例
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
  1. Access-Control-Allow-Headers
    作用: 允许客户端发送哪些自定义请求头
    详细说明: 当请求包含不在列表中的头部时,浏览器会阻止请求

    常见需要允许的头部:

    头部 作用 是否必需
    Authorization 认证令牌(Bearer token) ✓ 必需
    Content-Type 请求体类型(JSON/表单等) ✓ 必需
    Accept 客户端接受的响应类型 推荐
    X-Requested-With 标识 AJAX 请求 推荐
    Cache-Control 缓存控制 可选
    X-CSRF-Token CSRF 防护 可选

    示例:

    html 复制代码
    # 语法
    Access-Control-Allow-Headers: <header-name>[, <header-name>]*
    
    # 示例
    Access-Control-Allow-Headers: Content-Type, Authorization
    
    # 浏览器发送的预检请求
    OPTIONS /api/data HTTP/1.1
    Access-Control-Request-Headers: Content-Type, X-Custom-Header
    Origin: https://frontend.com
    
    # 服务器响应必须包含这些头
    Access-Control-Allow-Headers: Content-Type, X-Custom-Header
  2. Access-Control-Allow-Credentials
    作用: 是否允许携带凭证(cookies、HTTP认证)
    重要规则:

    • 不能与 Access-Control-Allow-Origin: * 同时使用
    • 必须与具体的域名配合

    语法:

    bash 复制代码
    Access-Control-Allow-Credentials: true | false
  3. Access-Control-Expose-Headers
    作用: 允许浏览器访问哪些响应头
    背景: 默认情况下,浏览器只能访问以下"简单响应头":

    Cache-Control

    Content-Language

    Content-Type

    Expires

    Last-Modified

    Pragma

    其他头部(如自定义头部)需要显式暴露。

    bash 复制代码
    # 语法
    Access-Control-Expose-Headers: <header-name>[, <header-name>]*
    
    # 示例:暴露自定义头
    Access-Control-Expose-Headers: X-Total-Count, X-Custom-Header
    
    # 前端可以访问
    fetch('/api/data')
      .then(response => {
        console.log(response.headers.get('X-Total-Count'));  // ✅ 可以访问
        console.log(response.headers.get('X-Custom-Header')); // ✅ 可以访问
      });
  4. Access-Control-Max-Age
    作用: 预检请求的缓存时间(秒)

    bash 复制代码
    # 语法
    Access-Control-Max-Age: <delta-seconds>
    
    # 示例
    Access-Control-Max-Age: 86400  # 缓存 24 小时
    Access-Control-Max-Age: 600    # 缓存 10 分钟
    
    # 效果:
    # 1. 浏览器缓存预检响应结果
    # 2. 在有效期内,相同请求不再发送预检请求
    # 3. 减少网络请求,提高性能
    
    # 建议值:
    # - 开发环境:300(5分钟)
    # - 生产环境:86400(24小时)
  5. Vary
    作用: 正确缓存不同来源的响应

    bash 复制代码
    # ❌ 没有设置 Vary: Origin,可能导致缓存污染
    # 用户A访问后,用户B可能看到A的CORS设置
    
    # ✅ 正确配置
    Access-Control-Allow-Origin: https://frontend.com
    Vary: Origin

总结

CORS 错误总是服务器配置问题,浏览器只是在执行安全策略保护用户安全。

调整后测试环境CORS配置:

xml 复制代码
        <httpProtocol>
            <customHeaders>
			    <add name="Access-Control-Allow-Origin" value="*" />
				<add name="Access-Control-Allow-Credentials" value="false" />
				<add name="Access-Control-Allow-Headers" value="*" />
				<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
				<add name="Access-Control-Expose-Headers" value="*" />
            </customHeaders>
        </httpProtocol>
相关推荐
郑州光合科技余经理2 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
feifeigo1232 天前
matlab画图工具
开发语言·matlab
dustcell.2 天前
haproxy七层代理
java·开发语言·前端
norlan_jame2 天前
C-PHY与D-PHY差异
c语言·开发语言
多恩Stone2 天前
【C++入门扫盲1】C++ 与 Python:类型、编译器/解释器与 CPU 的关系
开发语言·c++·人工智能·python·算法·3d·aigc
QQ4022054962 天前
Python+django+vue3预制菜半成品配菜平台
开发语言·python·django
遥遥江上月2 天前
Node.js + Stagehand + Python 部署
开发语言·python·node.js
m0_531237172 天前
C语言-数组练习进阶
c语言·开发语言·算法
Railshiqian2 天前
给android源码下的模拟器添加两个后排屏的修改
android·开发语言·javascript
雪人不是菜鸡2 天前
简单工厂模式
开发语言·算法·c#