跨域访问CORS

    • 原理
      • 基本概念
      • 简单请求
      • 非简单请求(预检请求)
    • 代码实现
      • 服务器端Cors的关键配置
      • 服务端解析预检请求
      • 服务端填充响应
    • 抓包分析

原理

基本概念

在浏览器安全模型中,同源策略是最重要的安全基石。
一个“域”是由3个要素组成的:

  • 协议(如:http 或 https)
  • 主机(Host,如 www.example.com 或 127.0.0.1)
  • 端口(Port,如 80 或 8080)

只要这三个完全一致,就是同源的。
例如

  • http://example.com:80 和 http://example.com:8080 是不同源
  • http://example.com 和 https://example.com 是不同源

下面是官网解释跨域的图解:
在这里插入图片描述

两种请求:浏览器将 CORS 请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

简单请求

按照 W3C 的 CORS 规范,只有完全满足「安全要求」的跨域请求,浏览器才会把它直接当成简单请求,直接发送给服务端,不需要先发 OPTIONS。
必须同时满足以下条件

  1. 请求方法必须是(GET/HEAD/POST)三者之一
  2. 请求头不能超出以下几个字段(Accept、Accept-Language、Content-Language、Content-Type)等
  3. Content-Type(如果存在的话),其值只能是application/x-www-form-urlencoded、multipart/form-data、text/plain

非简单请求(预检请求)

非简单请求是指那些对服务器有特殊要求的请求,例如:

  • 使用PUT或DELETE方法
  • 设置Content-Type为application/json
    即不满足简单请求的条件的都是预检请求(非简单请求)。

对于这类请求,浏览器会在正式通信前额外发送一次HTTP查询请求(即预检请求),这个过程叫做预检(Preflight)。该请求会确认:

  1. 当前网页域名是否在服务器的许可名单中
  2. 允许使用的HTTP方法和头信息字段
    只有在获得服务器肯定答复后,浏览器才会发出正式的XMLHttpRequest请求,否则将报错。

“预检请求”用的请求方法是 OPTIONS,表示这个请求是用来询问的。头信息里面,关键字是 Origin,表示请求来自哪个源。
除了 Origin 字段,“预检请求”的头信息包括两个特殊字段。
Access-Control-Request-Method:必须字段,列出浏览器的 CORS 请求会用到哪些 HTTP 方法;
Access-Control-Request-Headers:这个字段是一个逗号 , 分隔的字符串,指定浏览器 CORS 请求会额外发送的头信息字段,上面示例是 X-Custom-Header。

代码实现

CORS(Cross-Origin Resource Sharing,跨域资源共享)通过在响应头里加上一组特殊字段来告诉浏览器,这个资源允许被某些源访问。

服务器端Cors的关键配置

struct CorsConfig 
{std::vector<std::string> allowedOrigins;//允许哪些域名可以访问std::vector<std::string> allowedMethods; //允许哪些方法可以跨域调用std::vector<std::string> allowedHeaders; //允许前端请求里带哪些请求头bool allowCredentials = false; //不允许携带Cookie/Authorization header/TLS client cert 这类凭证信息int maxAge = 3600;             //浏览器缓存预检请求的最大时长, 1 小时内同样的跨域请求只会发送一次 OPTIONS,之后直接用缓存的结果static CorsConfig defaultConfig() {CorsConfig config;config.allowedOrigins = {"*"}; //这里允许的是所有域名config.allowedMethods = {"GET", "POST", "PUT", "DELETE", "OPTIONS"}; //在预检请求(OPTIONS)的响应里告诉浏览器:后端接受哪些方法config.allowedHeaders = {"Content-Type", "Authorization"}; //允许前端带Content-Type(比如 application/json)和Authorization(携带JWT Token等)return config;}
};

服务端解析预检请求

处理客户端发来的请求的流程如下:

  1. 判断是否是预检请求,如果是,进入下一步;否则不做处理(正常的请求,继续后续的处理流程,响应)
  2. 检查当前请求的源是否被允许,如果允许当前请求源则在响应头中添加该源字段,状态码为204 No content,响应体为空,进入下一步
  3. 直接抛出特殊的响应对象(中断后续的处理流程)

总结:如果是预检请求,设置Cors的相关字段,直接返回;否则就进入正常的处理流程。

/***  @brief 请求前钩子,所有请求进来时都会先执行* 如果是跨域的 OPTIONS 预检请求,直接构造响应并抛出,跳过后续中间件/路由逻辑。*/
void CorsMiddleware::before(HttpRequest& request) 
{LOG_DEBUG << "CorsMiddleware::before - Processing request";// 如果是浏览器发起的预检请求(CORS Preflight)if (request.method() == HttpRequest::Method::kOptions) {LOG_INFO << "Processing CORS preflight request";HttpResponse response;  // 创建预检响应handlePreflightRequest(request, response);// 直接中断后续处理流程,抛出特殊的响应对象throw response;}
}/*** @brief 处理 CORS 预检请求(OPTIONS)* 会校验 Origin,并返回允许的跨域头*/
void CorsMiddleware::handlePreflightRequest(const HttpRequest& request, HttpResponse& response) 
{   // 从请求头获取 Originconst std::string& origin = request.getHeader("Origin");// 校验是否允许跨域if (!isOriginAllowed(origin)) {LOG_WARN << "Origin not allowed: " << origin;response.setStatusCode(HttpResponse::k403Forbidden);return;}// 添加允许的跨域头,对预检请求返回 204 No Content;//即响应体为空,对应返回的是options字段的预检请求的响应addCorsHeaders(response, origin);response.setStatusCode(HttpResponse::k204NoContent);LOG_INFO << "Preflight request processed successfully";
}/*** @brief 检查给定 Origin 是否在允许列表里* @param origin 来自浏览器请求头的 Origin* @return true 如果允许跨域,否则 false*/
bool CorsMiddleware::isOriginAllowed(const std::string& origin) const 
{return config_.allowedOrigins.empty() || std::find(config_.allowedOrigins.begin(), config_.allowedOrigins.end(), "*") != config_.allowedOrigins.end() ||std::find(config_.allowedOrigins.begin(), config_.allowedOrigins.end(), origin) != config_.allowedOrigins.end();}/*** @brief 给响应添加标准的 CORS 头信息* @param response 当前响应对象* @param origin 本次请求允许的 Origin*/
void CorsMiddleware::addCorsHeaders(HttpResponse& response, const std::string& origin) 
{try {   // 设置允许的 Originresponse.addHeader("Access-Control-Allow-Origin", origin);// 是否允许携带 cookieif (config_.allowCredentials) {response.addHeader("Access-Control-Allow-Credentials", "true");}// 设置允许的方法列表,以,分割if (!config_.allowedMethods.empty()) {response.addHeader("Access-Control-Allow-Methods", join(config_.allowedMethods, ", "));}// 设置允许的自定义请求头列表if (!config_.allowedHeaders.empty()) {response.addHeader("Access-Control-Allow-Headers", join(config_.allowedHeaders, ", "));}// 设置预检结果的缓存时间(单位:秒)response.addHeader("Access-Control-Max-Age", std::to_string(config_.maxAge));LOG_DEBUG << "CORS headers added successfully";} catch (const std::exception& e) {LOG_ERROR << "Error adding CORS headers: " << e.what();}
}
/*** @brief 工具函数:把字符串数组用指定分隔符拼接起来* @param strings 字符串列表* @param delimiter 分隔符,如 ", "* @return 拼接后的字符串*/
std::string CorsMiddleware::join(const std::vector<std::string>& strings, const std::string& delimiter) 
{std::ostringstream result;for (size_t i = 0; i < strings.size(); ++i) {if (i > 0) result << delimiter;result << strings[i];}return result.str();
}

服务端填充响应

这里的响应指的是正常处理客户端发来的请求后,在最终的响应头中添加CORS的相关信息

/*** @brief 请求后钩子,正常请求处理完毕后执行。* 不管是否跨域,都会在最终响应头里加上 CORS 相关头信息。*/
void CorsMiddleware::after(HttpResponse& response) 
{LOG_DEBUG << "CorsMiddleware::after - Processing response";// 直接添加CORS头,简化处理逻辑if (!config_.allowedOrigins.empty()) {// 如果允许所有源if (std::find(config_.allowedOrigins.begin(), config_.allowedOrigins.end(), "*") != config_.allowedOrigins.end()) {addCorsHeaders(response, "*");} else {// 简单处理:只取第一个允许的来源(可以按需改成匹配实际请求来源)addCorsHeaders(response, config_.allowedOrigins[0]);}}
}

抓包分析

在这里插入图片描述
在这里插入图片描述
上图展示了请求与响应的抓包分析数据:当客户端向服务器请求加载登录页面时,服务器不仅会在响应体中返回HTML文件,还会在响应头中附带CORS配置信息供浏览器解析。
CORS 详解,终于不用担心跨域问题了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/87482.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/87482.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/87482.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FastAPI开发教程

FastAPI 是一个现代、高性能的 Python Web 框架&#xff0c;专为构建 APIs 设计。它基于 Python 类型提示&#xff0c;支持异步编程&#xff0c;并提供自动生成的交互式文档&#xff08;Swagger UI 和 ReDoc&#xff09;。以下是 FastAPI 开发的核心指南&#xff1a; 1. 安装 …

基于Spring Boot + MyBatis-Plus + Thymeleaf的评论管理系统深度解析

你好呀&#xff0c;我是小邹。 个人博客系统日渐完善&#xff0c;现在的文章评论以及留言数量逐渐增多&#xff0c;所以今天重构了管理后台的评论列表&#xff08;全量查询 -> 分页条件搜索&#xff09;。 示例图 网页端手机端一、系统架构设计与技术选型 系统采用前后端分离…

sqlmap学习笔记ing(1.Easy_SQLi(时间,表单注入))

题解 根据题目提示&#xff0c;应为SQL注入&#xff0c;题目页面只有一个表单&#xff0c;用sqlmap进行表单注入。 使用--forms参数进行自动化表单注入&#xff0c;逐步得到flag。 ### 总结参数作用&#xff1a; -u 指定目标URL。 -C 指定列名&#xff08;多个…

SciPy 安装使用教程

一、SciPy 简介 SciPy&#xff08;Scientific Python&#xff09;是基于 NumPy 的开源科学计算库&#xff0c;提供了数值积分、优化、信号处理、线性代数、统计分析等高级科学计算功能。它是构建 Python 科学计算生态系统的核心组件之一&#xff0c;常用于科研、工程、数据分析…

【AI大模型】通义大模型与现有企业系统集成实战《CRM案例分析与安全最佳实践》

简介&#xff1a; 本文档详细介绍了基于通义大模型的CRM系统集成架构设计与优化实践。涵盖混合部署架构演进&#xff08;新增向量缓存、双通道同步&#xff09;、性能基准测试对比、客户意图分析模块、商机预测系统等核心功能实现。同时&#xff0c;深入探讨了安全防护体系、三…

如何进行需求全周期管理

实现高效的需求全周期管理&#xff0c;应从以下五个方面入手&#xff1a;1、建立系统化需求来源渠道、2、设置清晰的评审与优先级策略、3、加强执行过程的协同与跟踪、4、闭环需求验收与上线反馈、5、构建长期的需求知识沉淀机制。 其中&#xff0c;“加强执行过程的协同与跟踪…

热传导方程能量分析与边界条件研究

题目 问题 10. (a) 考虑热传导方程在 J = ( − ∞ , ∞ ) J = (-\infty, \infty) J=(−∞,∞) 上,证明“能量” E ( t ) = ∫ J u 2 ( x , t ) d x E(t) = \int_{J} u^{2}(x,t) dx E(t)=∫J​u2(x,t)dx (8) 不增加;进一步证明,除非 u ( x , t ) = 常数 u(x,t) = \text{常…

【AI News | 20250702】每日AI进展

AI Repos 1、LLM-RL-Visualized 提供100余张原创架构图&#xff0c;全面涵盖了 LLM (大语言模型)、VLM (视觉语言模型) 等大模型技术。内容深度解析了训练算法&#xff08;如 RL、RLHF、GRPO、DPO、SFT、CoT 蒸馏等&#xff09;、效果优化策略&#xff08;如 RAG、CoT&#xf…

安徽省企业如何做信创产品认证?信创认证流程与费用详解

安徽省作为长三角一体化发展的重要成员&#xff0c;正大力推进信息技术应用创新&#xff08;信创&#xff09;产业发展。依托合肥“中国声谷”、芜湖机器人及智能装备基地等产业集群&#xff0c;以及省内对信创产业的政策扶持&#xff0c;企业通过信创认证后&#xff0c;能更好…

百度文心 ERNIE 4.5 开源:开启中国多模态大模型开源新时代

百度文心 ERNIE 4.5 开源&#xff1a;开启中国多模态大模型开源新时代 随着DeepSeek-R1的横空出示&#xff0c;越来越多大公司开始开源模型&#xff0c;像DeepSeek R1发布的时候Kimi同步开源了技术文档&#xff0c;随着R1推动着思维链推理技术的发展&#xff0c;开源社区也出现…

22、企业项目管理(Project)全体系构建:从基础框架到智能防呆的完整解决方案

项目管理能力——企业VUCA战略落地的核心枢纽 在VUCA&#xff08;乌卡时代&#xff0c;即VUCA时代&#xff0c;是指人们生活在一个不稳定性、不确定性、复杂性、模糊性的时代、境况或者世界中。vuca是volatility&#xff08;易变性VUCA&#xff09;&#xff0c;uncertainty&am…

分布式定时任务:Elastic-Job-Lite

Elastic-Job-Lite 是一款由 Apache 开源的轻量级分布式任务调度框架&#xff0c;属于 ShardingSphere 生态体系的一部分。它专注于分布式任务调度&#xff0c;支持弹性伸缩、分片处理、高可用等特性&#xff0c;且不依赖中心化架构。 一、基础 &#xff08;一&#xff09;核心特…

记录一次生产环境ActiveMQ无法启动的问题

这次遇到一个问题&#xff0c;是ActiveMQ无法启动的&#xff0c;跟以往的现象不一样。这次是在服务器重启后出异常。 1、启动ActiveMQ时提示&#xff1a;activemq/data/kahadb/db.data&#xff08;输入输出错误&#xff09;&#xff0c;NotFoundFileException异常 2、想着不应该…

大型语言模型幻觉检测相关综述

背景 1.1 幻觉检测的定义与范围 大型语言模型&#xff08;LLMs&#xff09;中的幻觉检测 是指系统性地识别由LLMs生成的事实错误或无意义输出的任务&#xff0c;而无需依赖外部证据 [Li et al., 2024; Zhang et al., 2024]。这项任务对于确保LLM生成内容的可靠性和可信度至关…

Python爬虫与数据可视化教程

对于经常写爬虫的技术来说了&#xff0c;可视化大大的提高工作效率&#xff0c;可以让获取的数据更直观的展示在面前&#xff0c;下面我将通过具体实操给大家展示下多种可视化具体教程&#xff0c;希望能都帮助大家。 下面是一个完整的Python爬虫和数据可视化解决方案&#xff…

【GHS】Green Hills软件MULTI-IDE的安装教程

前言&#xff1a;MULTI-IDE作为一款Green Hills开发的支持C/C、Ada等语言的嵌入式开发环境&#xff0c;由于其优异的性能&#xff0c;所以在汽车电子软件的开发中占有重要地位。但是这款IDE需要付费使用&#xff0c;对于个人学习而言不太友好&#xff0c;所以这里介绍一款PJ版本…

Web攻防-文件上传黑白名单MIMEJS前端执行权限编码解析OSS存储分域名应用场景

知识点&#xff1a; 1、WEB攻防-文件上传-前端&黑白名单&MIME&文件头等 2、WEB攻防-文件上传-执行权限&解码还原&云存储&分站等 3、WEB攻防-文件上传-JS提取&特定漏洞&第三方编辑器 4、WEB攻防-文件上传-思维导图形成 常规文件上传&#xff1a…

Odoo系统大型业务优化实战

目录 背景说明ORM与模型优化数据量处理策略接口与报表优化系统架构优化监控与诊断工具项目实战总结&#xff08;案例&#xff09;后续优化建议性能优化检查清单总结 一、背景说明 在 Odoo 项目中&#xff0c;随着业务不断扩展&#xff0c;系统常常面临如下挑战&#xff1a; …

【2.4 漫画SpringBoot实战】

🚀 漫画SpringBoot实战 🎯 学习目标:掌握SpringBoot企业级开发,从零到一构建现代化Java应用 📋 目录 SpringBoot核心特性自动配置原理Web开发实战数据访问与事务监控与部署🎭 漫画引言 小明: “为什么SpringBoot这么受欢迎?” 架构师老王: “SpringBoot就像全自动…

美国站群服务器的优势和应用与选择指南

在当今数字化时代&#xff0c;互联网业务的蓬勃发展促使各类企业和个人不断寻求高效、稳定且功能强大的网络解决方案。美国站群服务器作为一种备受瞩目的网络基础设施&#xff0c;正逐渐成为众多从事跨境电商、搜索引擎优化&#xff08;SEO&#xff09;、内容分发、数据采集等业…