一文带你理清同源和跨域

news2024/10/23 0:46:15

1、概述

前后端数据交互经常会碰到请求跨域,什么是跨域,为什么需要跨域,以及常用有哪几种跨域方式,这是本文要探讨的内容。
image-20240618160438055
同源策略(英文全称 Same origin policy)是浏览器提供的一个安全功能。同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。

同源策略是一种约定,它是浏览器最核心也是最基本的安全功能。出于安全考虑,浏览器限制从JS脚本发起的跨源HTTP请求。

通俗的理解:浏览器规定,A 网站的 JavaScript,不允许和非同源的网站 C 之间,进行资源的交互,例如:

①无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB。

②无法接触非同源网页的 DOM。

③无法向非同源地址发送 Ajax 请求。

同源指的是两个 URL 的协议、域名、端口一致,反之,则是跨域。出现跨域的根本原因:浏览器的同源策略不允许非同源的 URL 之间进行资源的交互。

例如网页(http://www.test.com/index.html)和接口(http://www.api.com/userlist),非同源的URL,浏览器允许发起跨域请求,但是,跨域请求回来的数据,会被浏览器拦截,无法被页面获取到。

image-20240618152346498

2、为什么要跨域?

跨域是浏览器受同源(协议、域名、端口)策略的限制,不允许不同源的站点之间进行某些操作(如发送ajax请求,操作dom,读取cookie),如果不进行特殊配置是不能操作成功的,并且控制台会报如下跨域错误:

``No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘xxxxxx’ is therefore not allowed access`

跨域的根本原因是浏览器的“同源策略”,同源 就是【协议+域名+端口号】相同,即为同源,只能向同源的服务发起AJAX请求。

image-20240618152627312

源1源2是否同源
a.comb.com🚫不同源,域名不同
http://a.comhttps://a.com🚫不同源,协议不同
a.com:80a.com:443🚫不同源,端口不同
gg.coma.gg.com🚫不同源,子域名不同
a.com/ssa.com/s2同源

可通过location.originwindow.origin获取当前文档的源

为什么要同源呢?

这是浏览器故意设计的,是浏览器的基本安全策略,否则会很容易受到XSS、CSRF攻击。只能向同源的服务发起AJAX请求,不可跨域请求,会被浏览器拦截。

有哪些限制规则呢?

  • ✅ 访问其他源的图片、CSS、JS是可以的,允许<img src="url"><link href="url"><script src="url">元素获取的其他源的资源。
  • ✅ Form表单可以跨域提交,表单的提交只是提交数据无需返回,浏览器认为是安全的。
  • 🚫 AJAX不可以向其他源发送网络请求,会被浏览器拦截。注意拦截的不是请求,而是响应,服务端依然是可以收到请求的。
  • 🚫 仅可访问自己域的cookie、localStorage、DOM树,不能访问Iframe嵌入的其他页面内部内容。

image-20240618152717403

3、如何实现跨域?

跨域请求(Cross-Origin Request),简称CORS,是指在Web开发中,当一个Web页面向不同源(域名、协议或端口)的服务器发起请求时,浏览器会遵循同源策略(Same-Origin Policy)的限制,对这些跨源请求进行限制。由于浏览器的同源策略限制,跨域请求默认是被禁止的,同源策略要求请求的协议、域名和端口必须完全一致,否则会被浏览器拦截。

随着互联网越来越复杂,需求也越来越多,跨域请求就很常见了。我们知道了跨域是浏览器的同源限制,就可以针对性的想办法了。

跨域

本文主要针对最常用的三种进行讲解,其他的可以自行参考相关文章。

3.1、JSONP跨域

这是一种传统的跨域请求办法,借助于<script>标签元素,因为<script>src可以访问任何站点的资源。当然这需要服务端对应接口支持JSONP(JSON with padding)协议,所以是需要双方约定好,所以浏览器认为这是安全的。

  • 优点是兼任IE,实现跨域。
  • 缺点是不能控制请求过程,仅支持GET方式请求。因为只是一个<script>标签,浏览器自动发起的资源请求。

JSONP(JSON with Padding)是JSON的一种”使用模式“,是一种非官方的协议,用于解决浏览器的跨域数据访问的问题。

📢前端具体实现过程:

  • 1、申明一个全局的回调函数“getData”来接收数据。
  • 2、动态创建一个<script>标签,src为要跨域的API地址,URL中带上回调参数“callback=getData”。
  • 3、服务端收到请求后,动态生成一个脚本,脚本内容是一个字符串,由回调+返回的数据构成:“getData('data')”。
  • 4、本地执行远程脚本,回调函数“getData”运行,就得到了想要的数据。
<script src="http:www.thrid.com/cors/api?q=key&callback=back"></script>
<script>
  function back(data) {
    console.log(data);
  }
</script>

JSONP的实现:

function jsonp(url, args, cbName) {
  return new Promise((resolve, reject) => {
    const ele = document.createElement('script');
    window[cbName] = (data) => {
      resolve(data);
      document.body.removeChild(ele);
    }
    args = { ...args, callback: cbName };
    ele.src = `${url}?${Object.keys(args).map(k => `${k}=${args[k]}`).join('&')}`;
    document.body.appendChild(ele);
  });
}
//使用,api为360的公开接口
jsonp('https://sug.so.360.cn/suggest', { format: 'jsonp', word: 'china' }, 'search')
  .then(function (data) {
    console.log(data)
  });

3.2、CORS跨域

CORS是什么?—— 跨域资源共享 (cross-origin resource sharing),让AJAX可以跨域访问数据。这是为了满足跨域请求的需求,W3C新增加的特性,需要服务端的支持,不支持IE8/9。

当浏览器发送一个跨域请求时,它会首先发送一个预检请求(OPTIONS请求),检查后端是否支持跨域请求。这个预检请求会包含一些CORS相关的HTTP头,如Origin、Access-Control-Request-Method和Access-Control-Request-Headers。后端收到预检请求后,会检查请求中的Origin头,与自己在CORS配置中设置的allowedOrigins进行对比,如果匹配成功,就会在响应中设置相应的CORS头,如Access-Control-Allow-Origin、Access-Control-Allow-Methods和Access-Control-Allow-Headers等。

一旦预检请求通过,浏览器就会发送实际的跨域请求。在接收到实际请求的响应后,浏览器会再次检查响应中的CORS头,确保它们与预检请求中的设置一致。如果一切正常,浏览器就会允许前端JavaScript代码访问响应中的数据。

通过这种方式,后端通过显式配置CORS参数,告知浏览器哪些源有权访问其资源,从而实现了跨域访问的功能。这既保证了安全性(只允许指定的源进行访问),又提供了灵活性(可以根据需要配置不同的CORS策略)。

根据请求方式,浏览器将CORS分为两种情况:

  • 简单请求(安全请求):只支持GET、POST、HEAD,Header只支持部分字段。
  • 复杂请求(其他请求):简单请求以外的其他跨域请求。
🔵简单请求

基本原理就是在请求头加入一个身份来源标识,服务端根据这个标识来判等是否允许访问,如果允许则给一个允许的标记并返回响应。

  • 只支持GET、POST、HEAD。
  • header —— 我们仅能设置基础的安全字段:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type 的值为 application/x-www-form-urlencoded,multipart/form-data 或 text/plain。

📢具体过程比较简单,前端只要在Header加入“Origin”即可:

  • 请求头Header加入要跨域的源:origin:http://www.main.com
GET /api HTTP/1.1
Origin: http://www.main.com				//本次请求来自哪个源
Host: http://www.third.com				//请求的第三方API
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0
...
  • 服务端收到请求后检查Origin,如果同意请求则正常响应,同时在响应的Header中加入特殊的“Access-Control-Allow-Origin”字段,申明支持的源,也可以用“*”表示支持任何源访问。
  • 浏览器收到响应后会检查“Access-Control-Allow-Origin”,和当前源对比,如果不合法则会报错——跨域。
Access-Control-Allow-Origin: http://www.main.com		//请求允许的源
Access-Control-Allow-Credentials: true							//是否允许cookie,cors默认不发送cookie,如果要发送,还需AJAX中设置withCredentials
Access-Control-Expose-Headers: Content-Length,API-Key	//如果客户端想要访问其他非安全字段,则需要服务端明确定义哪些Header字段暴露出来
Content-Type: text/html; charset=utf-8

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

🟠复杂请求

不是简单请求的都称为复杂请求(非简单请求),如请求方法是PUT、DELETE,或Content-Type=application/json。相比于简单请求,复杂请求多了一次预请求。

预请求

  • 正式发送请求前,浏览器会自动发送一个预请求,问问服务端是否允许本次请求,如果回应允许才正式发送请求,后面就和简单请求相同了。
  • 预请求及其响应都没有body,采用OPTIONS方法。

image.png

JSONP 与`CORS 的对比

JSONP 是很早很成熟的解决方案,但是,只能进行 GET 请求,无法实现上传数据等操作。

反观:CORS 虽然分 预请求非预请求 ,但是,无疑支持的功能是非常强大的 !!!

3.3、Nginx反向代理

跨域是浏览器的保护机制,如果绕过浏览器,使用代理服务器去请求目标服务器上的数据,就不会受跨域影响。因此前端可以通过脚手架或webpack配置devSever下的proxy选项,将/api开头的请求转发到真实服务器上。

在生产环境下也可以使用nginx配置反向代理来解决跨域。

Nginx 则是通过反向代理的方式,(这里也需要自定义一个域名)这里就是保证我当前域,能获取到静态资源和接口,不关心是怎么获取的。

Nginx反向代理

配置下 hosts

127.0.0.1 local.test

配置 nginx

server {
        listen 80;
        server_name local.test;
        location /api {
            proxy_pass http://localhost:8080;
        }
        location / {
            proxy_pass http://localhost:8000;
        }
}

对于前端开发而言,大部分的跨域问题,都是通过代理解决的

代理适用的场景是:生产环境不发生跨域,但开发环境发生跨域

代理适用的场景是

4、小结

因为同源是浏览器的限制,跨域的方法无非就是绕过,或采用CORS。

跨域方案基本原理是否需要服务端支持
JSONP借助<script>标签的src,加上一个全局回调函数接收数据🟠需要服务端支持JSONP协议
CORSW3C标准支持的跨域方式,请求头添加Origin字段🟠需要服务端支持
WebSocketWebSocket可以实现浏览器与服务端的双向通信,没有跨域的困惑。推荐第三方库 Socket.io,可以很方便的建立与服务端的Socket通信。🟠需要服务端支持,支持WebSocket
iframe+postMessage使用window.postMessage()来实现窗口之间的通信🔵不需服务端处理,客户端绕过
服务端代理由自己的同源服务端代理第三方的请求🟠需要服务端支持,代理请求
nginx反向代理原理和服务端代理一样,用nginx配置一个代理服务🔵不需要服务端修改代码,需nginx支持
  • CORS支持所有类型的HTTP请求,是跨域HTTP请求的根本解决方案。
  • JSONP只支持GET请求,JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
  • 不管是Node中间件代理还是nginx反向代理,主要是通过同源策略对服务器不加限制。
  • 日常工作中,用得比较多的跨域方案是cors和nginx反向代理。

5、参考文章

So, JSONP or CORS? - Stack Overflow

浏览器的同源策略 - Web 安全 | MDN (mozilla.org)

跨源资源共享(CORS) - HTTP | MDN (mozilla.org)

跨域资源共享 CORS 详解

Fetch:跨源请求

九种跨域方式实现原理(完整版)

前端常见跨域解决方案(全)

我把7大跨域解决方法原理画成10张图,做成图解!

值得一看的35个Redis常用问题总结http://www.guosisoft.com/article/detail/243)

国思RDIF低代码快速开发平台(支持vue2、vue3)


一路走来数个年头,感谢RDIF框架的支持者与使用者,大家可以通过下面的地址了解详情。

官方网站:http://www.guosisoft.com/ http://www.rdiframework.net/

特别说明,框架相关的技术文章请以官方网站为准,欢迎大家收藏!

RDIF.vNext低代码快速开发框架由海南国思软件科技有限公司专业团队长期打造、一直在更新、一直在升级,请放心使用!

欢迎关注RDIF.vNext低代码快速开发框架官方公众微信(微信号:guosisoft),及时了解最新动态。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

海外盲盒小程序搭建过程的最大挑战:文化差异与本地化

一、引言 随着全球化的深入发展&#xff0c;跨境电商和海外市场的拓展成为许多企业的重要战略方向。盲盒小程序作为一种新兴的消费模式&#xff0c;也在海外市场展现出巨大的潜力。然而&#xff0c;在海外搭建盲盒小程序并非易事&#xff0c;文化差异与本地化问题是其搭建过程…

计算最大数位-第13届蓝桥杯省赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第87讲。 计算最大数位&…

Qwen2大模型微调入门实战-命名实体识别(NER)任务(完整代码)

Qwen2是通义千问团队最近开源的大语言模型&#xff0c;由阿里云通义实验室研发。 以Qwen2作为基座大模型&#xff0c;通过指令微调的方式做高精度的命名实体识别&#xff08;NER&#xff09;&#xff0c;是学习入门LLM微调、建立大模型认知的非常好的任务。 使用LoRA方法训练&…

MySQL快速安装(mysql8.0.30区别之前yum安装)

目录 一.初始化环境并解压 二.创建程序用户管理 三.修改mysql目录和配置文件的权限 四.修改配置文件 五.设置环境变量&#xff0c;申明/宣告mysql命令便于系统识别 六.初始化数据库 七.设置系统识别&#xff0c;进行操作 八.初始化数据库密码 九.用户并设置密码 十.赋…

机器学习模型评估之校准曲线

模型校准曲线&#xff08;Calibration Curve&#xff09;&#xff0c;也称为可靠性曲线&#xff08;Reliability Curve&#xff09;或概率校准曲线&#xff08;Probability Calibration Curve&#xff09;&#xff0c;是一种评估分类模型输出概率准确性的图形工具。它可以帮助我…

STM32 串口通讯

使用STM32的串口通讯&#xff0c;接收串口助手的数据&#xff0c;并且将接收到的数据返回串口&#xff0c;重定义printf功能。 配置引脚信息 由于每次新建工程都需要配置信息&#xff0c;比较麻烦&#xff0c;好在STM32CubeIDE提供了导入.ioc文件的功能&#xff0c;可以帮我们…

达梦8 兼容MySQL语法支持非分组项作为查询列

MySQL 数据库迁移到达梦后&#xff0c;部分GROUP BY语句执行失败&#xff0c;报错如下&#xff1a; 问题原因&#xff1a; 对于Oracle数据库&#xff0c;使用GROUP BY时&#xff0c;SELECT中的非聚合列必须出现在GROUP BY后面&#xff0c;否则就会报上面的错误&#xff0c;达梦…

基于python+tkinter(Gui)的学生信息管理系统

博主介绍&#xff1a; 大家好&#xff0c;本人精通Java、Python、C#、C、C编程语言&#xff0c;同时也熟练掌握微信小程序、Php和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验&#xff0c;能够为学生提供各类…

[创业之路-119] :制造业企业的必备管理神器-ERP-主要功能模块说明与系统架构

目录 一、ERP功能的标准化 二、常见的ERP标准化功能 2.1 基础档案 2.2 供应链 2.3 人力资源管理 2.4 资产管理 2.5 生产制造 2.6 财务会计 2.7 管理会计 2.8 CRM客户管理管理 2.9 商业智能分析 三、常见的ERP软件供应商 国内ERP软件供应商 国外ERP软件供应商 四…

2024考古之还在用原始JDBC开发 手搓 案例 实现一个模块的增删改

JDBC案例 将来如果完成的话 就代表对JDBC里面的知识点全部融会贯通了 其实就是对数据的增删改查 我们入门做不出来前端的内容 很正常 准备环境 建表 use mybatis;create table tbl_brand (id int primary key auto_increment,brand_name varchar(20),company_name varcha…

在hue中使用ooize调度ssh任务无法执行成功,无法查看错误

ssh执行失败&#xff0c;但是hue没有给出明确的错误原因&#xff1a; 经过经验分析&#xff0c;原来是服务器上的sh文件用的是doc/window格式&#xff0c;需要使用notepad将格式改为unix之后就可以正常执行。 特此记录&#xff0c;避免遗忘知识点

图标设计新手手册:应用图标尺寸比例全解析

通常我们在App Store中寻找新的应用程序时&#xff0c;首先会快速扫描搜索栏中的一些关键词&#xff0c;然后选择感兴趣的应用程序&#xff0c;在选定的应用页面中查看具体信息&#xff0c;最后决定是否下载。在这一系列操作中&#xff0c;APP图标的大小比例是影响用户体验的关…

大腾智能,基于云原生的国产工业协同平台

大腾智能是一家基于云原生的国产工业软件与数字化协同平台&#xff0c;专注于推动企业数字化转型与升级&#xff0c;为企业提供一系列专业、高效的云原生数字化软件及方案&#xff0c;推动产品设计、生产及营销展示的革新&#xff0c;实现可持续发展。 大腾智能旗下产品 3D模型…

前端构建工具用得好,构建速度提升 10 倍

今天来盘点一下前端构建工具。 Turbopack Turbopack&#xff0c;由Vercel开源&#xff0c;是下一代高性能的JavaScript应用构建工具&#xff0c;目前用于 Next.js 中。Turbopack旨在通过革新JavaScript应用的打包流程来显著提升应用性能&#xff0c;它专注于缩短加载时间&…

小阿轩yx-Tomcat 部署及优化

小阿轩yx-Tomcat 部署及优化 Tomcat 概述 免费的、开放源代码的Web应用服务器Apache软件基金会(Apache Software Foundation)Jakarta项目中的一个核心项目由Apache、Sun和一些公司及个人共同开发而成深受Java爱好者的喜爱,并得到部分软件开发商的认可目前比较流行的Web应用服…

强化学习——基本概念

何为强化学习 机器学习的一大分支 强化学习&#xff08;Reinforcement Learning&#xff09;是机器学习的一种&#xff0c;它通过与环境不断地交互&#xff0c;借助环境的反馈来调整自己的行为&#xff0c;使得累计回报最大。强化学习要解决的是决策问题——求取当前状态下最…

sql资料库

1、distinct(关键词distinct用于返回唯一不同的值)&#xff1a;查询结果中去除重复行的关键字 select distinct(university) from user_profile select distinct university from user_profile distinct是紧跟在select后面的&#xff0c;不能在其他位置&#xff0c;不然就…

充电学习— 9、Typec Pd

GND&#xff1a;线缆接地 TX RX&#xff1a;数据流data传输&#xff0c;支持2.0 3.0 speed兼容 VBUS&#xff1a;线缆cable电源&#xff0c;bus power CC&#xff1a;电缆cable的连接、方向、角色检测和当前模式的配置通道&#xff1b; 有emark时&#xff0c; 一个成为VCONN&am…

Flutter【组件】按钮

简介 flutter 按钮组件。提供一种封装按钮组件的思路&#xff0c;并不支持过多的自定义属性。根据使用场景及设计规范进行封装&#xff0c;使用起来比较方便。 github地址&#xff1a;https://github.com/ThinkerJack/jac_uikit pub地址&#xff1a;https://pub.dev/package…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 密码解密(100分) - 三语言AC题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; &#x1f…