浏览器访问跨域

文章目录

发现问题

在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>
相关推荐
Dev7z6 分钟前
基于 MATLAB 的铣削切削力建模与仿真
开发语言·matlab
不能隔夜的咖喱12 分钟前
牛客网刷题(2)
java·开发语言·算法
小天源19 分钟前
Error 1053 Error 1067 服务“启动后立即停止” Java / Python 程序无法后台运行 windows nssm注册器下载与报错处理
开发语言·windows·python·nssm·error 1053·error 1067
肉包_5111 小时前
两个数据库互锁,用全局变量互锁会偶发软件卡死
开发语言·数据库·c++
大空大地20261 小时前
流程控制语句--if语句
开发语言
毕设源码-邱学长2 小时前
【开题答辩全过程】以 基于PHP的发热病人管理平台的设计与实现为例,包含答辩的问题和答案
开发语言·php
HellowAmy2 小时前
我的C++规范 - 线程池
开发语言·c++·代码规范
独自破碎E2 小时前
【BISHI9】田忌赛马
android·java·开发语言
czy87874752 小时前
const 在 C/C++ 中的全面用法(C/C++ 差异+核心场景+实战示例)
c语言·开发语言·c++
范纹杉想快点毕业2 小时前
实战级ZYNQ中断状态机FIFO设计
java·开发语言·驱动开发·设计模式·架构·mfc