百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

十大常见的「前端跨域」解决方案 前端跨域如何解决

bigegpt 2024-10-12 05:57 9 浏览

点击上方“Web前端进阶指南”关注我呦

跟程序员小强一起学前端

跨域在我们前端也是最常见的问题之一,作为一名前端开发人员,相信大家都知道跨域是因为浏览器的同源策略所导致的。

但是仅仅知道是没有用的,公司里很多同事都知道是因为浏览器的同源策略引起的,却不知根源,更不知如何去解决,他们经常在网站中引用iframe,虽说没有出现任何复杂性的问题,却也不去解决,后端给个接口,说跨域了,然后让他们去解决,不会啊,三番五次的问,而且这问题一阻碍就耗费了很多的时间,那么到底跨域是怎么产生的,作为我们前端人员必须去了解,去解决。

其实想知道产生这个问题的“大哥”,我们必须去了解浏览器的同源策略。

同源策略

同源策略是浏览器最核心也是最基本的安全功能,所有支持JavaScript的浏览器都会使用这个策略,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响,可以说,我们的Web是构建在同源策略基础之上的,反之,我们的浏览器也是针对同源策略的一种实现。

例如,我们在浏览器上打开两个页面,一个是头条,一个是悟空问答,当浏览器的头条页面去执行一个脚本文件的时候会检查这个脚本是属于那个页面的,就是所谓的检查是否同源,只有和头条同源的脚本才会被执行,如果不是同源,那么在请求数据时,浏览器就会报错,提示访问拒绝。

再说一个简单例子,当我们在写页面的时候,想在页面中调用别的网站的东西,比如图表,图片,内容文本的时候,发现放在当前页面的时候,有点不适合,想改一下,于是你就用js获取iframe里的文档元素,想去修改它,这时候就会发现浏览器报错。

想想如果没有同源策略,我可以在不同域的iframe之间直接访问,我可以直接把银行的网站用iframe嵌套到我得网站里,页面调整到和银行页面一样,你输入域名进来,看见的是银行网站页面,这时候你输入账号密码进行操作,我的主网站就可以跨域访问到银行页面的DOM节点,于是乎就拿到了你的账号密码,可怕不。

同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接受。

说到这,非同源就是在请求数据时,浏览器会拒绝请求,不让你用别的地方的东西。

所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

来个更直白的,我们用一张图给出下面URL同源检测的示例:

URL:http://pc.abc.com/index.html

这样就明白了浏览器同源策略的原理了吧[嘿嘿]

跨域

看完上面有的小伙伴就问,那不用不就行了吧,我不去别的访问请求,我就在同一个服务器访问请求不就行了,哎,你还年轻啊,不知道别人家的媳妇好啊[哈哈][哈哈],开玩笑的啊。还是自家媳妇好!

跨域的优势能充分地利用分布式集群系统,是某些服务压力分散到多台服务器上,就像我们一个团队做一个项目,分配下去,最后整合,这样效率就很高,但质量就得不到保证,同样的我们把某些服务分散到多台服务器,压力是小了,但安全性就得不到保证。

不跨域的前提是前台页面和后台服务器都在一个服务器上,前提是应用得小,服务器压力不会很大,好处就是安全性高,处理简单。

目前计算机行业正在向高集成、多并发、低耦合的方向发展,所有的基础服务都会以接口的方式提供,就像百度地图、微信、小程序、支付宝等,这样一来,就会牵扯到跨域,我们就必须去解决,处理好跨域和安全问题是猿们不许去做的事。

从上面我们知道是因为浏览器的同源策略引起了跨域,也正是有了跨域限制,我们才能安全上网,那有时候我们必须去做这件事,就是去请求别的资源,那怎么解决吗?于是乎就有了我这样的“好心人”写下了解决方法。

我来说说我解决过的跨域问题,没有解决过的我给你附上链接地址,大家可以去看看,张大神的博客也有。

跨域解决方案

1、 通过jsonp跨域

Jsonp是Json的一种“使用模式”,他就可以解决浏览器遇到的跨域问题,我们可以动态创建script,再请求一个带参网址实现跨域通信。用Jsonp请求得到的是JavaScript,相当于直接用JavaScript解析。

但是,只能实现get一种请求。

1.1、原生js实现:

服务器端返回:

handleCallback({"status": true, "user": "admin"})

1.2、AJAX实现:

1.3、vue.js实现

2、document.domain + iframe跨域

这个适合在主域名相同,子域名不同的情况下使用,这时候用它就显得很轻松了,我们可以在两个页面都通过js强制设置document.domain为基础主域,这样就实现了同域。

2.1、父窗口(http://www.test.com/a.html)

2.2、子窗口(http://child.com/b.html)

3、location.hash + iframe跨域

通过location.hash + iframe来解决跨域,就是说a页面想和b页面实现通信,可以通过c页面来实现,三个页面之前可以利用 iframe 的location.hash传值,相同域之间直接 js 访问来通信。

假如a和b不同域,b和c不同域,c和a同域,那么,c就可以通过 parent.parent 来访问a页面中所有的对象。

3.1、a.html:(http://www.test1.com/a.html)

3.2、b.html:(http://www.test2.com/b.html)

3.3、c.html:(http://www.test1.com/c.html)

4、 window.name + iframe跨域

在 iframe 中,window.name是一个固定的值,我们可以利用它实现跨域。只要你不关闭页面,来回之间跳转改变URL,window.name是不会改变的,而且每一个打开的页面都能获取并修改window.name的值。

4.1、a.html:(http://www.test1.com/a.html)

4.2、fuzhu.html:(http://www.test1.com/fuzhu.html)这是个辅助页面,啥也不用管。但是与a.html同域。

4.3、b.html:(http://www.test2.com/b.html)

<script>
    window.name = 'This is test2 data!';
</script>

通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

5、postMessage跨域

在h5中新增了postMessage方法,postMessage可以实现跨文档消息传输,我们可以通过Windows的message事件来监听发送跨文档消息传输内容。

主页面 A 通过 iframe 加载跨域页面 B,页面 B 加载完毕后需要获取主页面 A 保存在 localStorage 内的 jwt 令牌。

5.1、a.html :(http:/ /test1.com/a.html)

5.2、b.html (http:/ /test2.com/b.html)

6、跨域资源共享(CORS)

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

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

注意:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。

目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。

6.1、原生ajax实现

6.2、jQuery ajax实现

6.3、Vue框架

a) axios设置

axios.defaults.withCredentials = true

b)vue-resource设置

Vue.http.options.credentials = true

7、nginx代理跨域

个人觉得使用 nginx 是一种较为简单直接彻底的办法。

7.1、 nginx配置解决iconfont跨域

浏览器跨域访问js、css、img等常规静态资源被同源策略许可,但iconfont字体文件(eot|otf|ttf|woff|svg)例外,此时可在nginx的静态资源服务器中加入以下配置。

location / {
  add_header Access-Control-Allow-Origin *;
}

7.2、 nginx反向代理接口跨域

跨域原理: 同源策略是浏览器的安全策略,不是HTTP协议的一部分。服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题。

实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。

nginx具体配置:

前端代码示例:

var xhr = new XMLHttpRequest();

// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;

// 访问nginx中的代理服务器
xhr.open('get', 'http://www.domain1.com:81/?user=admin', true);
xhr.send();

8、Nodejs中间件代理跨域

通过Nodejs来进行代理接口。不过要实现这个前提是,前端开发环境必须运行在Nodejs服务中,所幸的现在前端的开发自动化工具都是建立在nodejs上的,所以也没必要顾虑这么多。

8.1、 非vue框架的跨域(2次跨域)

利用node + express + http-proxy-middleware搭建一个proxy服务器。

前端代码示例:

var xhr = new XMLHttpRequest();

// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;

// 访问http-proxy-middleware代理服务器
xhr.open('get', 'http://www.domain1.com:3000/login?user=admin', true);
xhr.send();

中间件服务器示例:

8.2、vue框架的跨域(1次跨域)

利用node + webpack + webpack-dev-server代理接口跨域。在开发环境下,由于vue渲染服务和接口代理服务都是webpack-dev-server同一个,所以页面与代理接口之间不再跨域,无须设置headers跨域信息了。

webpack.config.js部分配置:

9、WebSocket协议跨域

原理:原生WebSocket API使用起来不太方便,利用webSocket的API,可以直接new一个socket实例,然后通过open方法内send要传输到后台的值,也可以利用message方法接收后台传来的数据。后台是通过

new WebSocket.Server({port:3000})

实例,利用message接收数据,利用send向客户端发送数据。

9.1、前端代码示例:

Nodejs socket后台代码示例:

10、Flash跨域

年龄久远的程序员们用过,我也只是见过,没用过,我也来整理一下。

原理很简单,无须对Flash做任何处理,只要在目标域 b.domain.com 的根目录上放入一个策略文件crossdomain.xml即可。

Flash访问另一个域的数据,flash player 会自动从目标域根域加载策略文件 crossdomain.xml。

如果访问的数据所在的域在策略文件中,则数据将可访问。

10.1、建立crossdomain.xml

<?xml version="1.0"?>  
<!--http://abcd.com/crossdomain.xml-->  
<cross-domain-policy>  
   <allow-access-from domain="www.baidu.com" />       <!--只允许百度主域访问-->
   <allow-access-from domain="m.baidu.com" />         <!--只允许百度二级域m.baidu访问-->
   <allow-access-from domain="*.baidu.com" />          <!--只允许百度所有域访问-->
   <allow-access-from domain="*" />                  <!--无访问限制-->
</cross-domain-policy>

10.2、把文件 crossdomain.xml 放入被Flash访问的域(b.domain.com)根目录上即可。

总结

目前CORS已经成为主流的跨域解决方案,但由于其不安全性,个人觉得使用 nginx 是一种较为简单直接彻底的办法。具体看项目实战需求吧。

本文为‘Web前端进阶指南’原创,转载请说明出处,手动码字不易,喜欢的小伙伴们别忘了顺手点个赞加个关注哈,有什么不懂的下方留言评论或私信。谢谢大家哈!

感谢您的阅读!

相关推荐

得物可观测平台架构升级:基于GreptimeDB的全新监控体系实践

一、摘要在前端可观测分析场景中,需要实时观测并处理多地、多环境的运行情况,以保障Web应用和移动端的可用性与性能。传统方案往往依赖代理Agent→消息队列→流计算引擎→OLAP存储...

warm-flow新春版:网关直连和流程图重构

本期主要解决了网关直连和流程图重构,可以自此之后可支持各种复杂的网关混合、多网关直连使用。-新增Ruoyi-Vue-Plus优秀开源集成案例更新日志[feat]导入、导出和保存等新增json格式支持...

扣子空间体验报告

在数字化时代,智能工具的应用正不断拓展到我们工作和生活的各个角落。从任务规划到项目执行,再到任务管理,作者深入探讨了这款工具在不同场景下的表现和潜力。通过具体的应用实例,文章展示了扣子空间如何帮助用户...

spider-flow:开源的可视化方式定义爬虫方案

spider-flow简介spider-flow是一个爬虫平台,以可视化推拽方式定义爬取流程,无需代码即可实现一个爬虫服务。spider-flow特性支持css选择器、正则提取支持JSON/XML格式...

solon-flow 你好世界!

solon-flow是一个基础级的流处理引擎(可用于业务规则、决策处理、计算编排、流程审批等......)。提供有“开放式”驱动定制支持,像jdbc有mysql或pgsql等驱动,可...

新一代开源爬虫平台:SpiderFlow

SpiderFlow:新一代爬虫平台,以图形化方式定义爬虫流程,不写代码即可完成爬虫。-精选真开源,释放新价值。概览Spider-Flow是一个开源的、面向所有用户的Web端爬虫构建平台,它使用Ja...

通过 SQL 训练机器学习模型的引擎

关注薪资待遇的同学应该知道,机器学习相关的岗位工资普遍偏高啊。同时随着各种通用机器学习框架的出现,机器学习的门槛也在逐渐降低,训练一个简单的机器学习模型变得不那么难。但是不得不承认对于一些数据相关的工...

鼠须管输入法rime for Mac

鼠须管输入法forMac是一款十分新颖的跨平台输入法软件,全名是中州韵输入法引擎,鼠须管输入法mac版不仅仅是一个输入法,而是一个输入法算法框架。Rime的基础架构十分精良,一套算法支持了拼音、...

Go语言 1.20 版本正式发布:新版详细介绍

Go1.20简介最新的Go版本1.20在Go1.19发布六个月后发布。它的大部分更改都在工具链、运行时和库的实现中。一如既往,该版本保持了Go1的兼容性承诺。我们期望几乎所...

iOS 10平台SpriteKit新特性之Tile Maps(上)

简介苹果公司在WWDC2016大会上向人们展示了一大批新的好东西。其中之一就是SpriteKitTileEditor。这款工具易于上手,而且看起来速度特别快。在本教程中,你将了解关于TileE...

程序员简历例句—范例Java、Python、C++模板

个人简介通用简介:有良好的代码风格,通过添加注释提高代码可读性,注重代码质量,研读过XXX,XXX等多个开源项目源码从而学习增强代码的健壮性与扩展性。具备良好的代码编程习惯及文档编写能力,参与多个高...

Telerik UI for iOS Q3 2015正式发布

近日,TelerikUIforiOS正式发布了Q32015。新版本新增对XCode7、Swift2.0和iOS9的支持,同时还新增了对数轴、不连续的日期时间轴等;改进TKDataPoin...

ios使用ijkplayer+nginx进行视频直播

上两节,我们讲到使用nginx和ngixn的rtmp模块搭建直播的服务器,接着我们讲解了在Android使用ijkplayer来作为我们的视频直播播放器,整个过程中,需要注意的就是ijlplayer编...

IOS技术分享|iOS快速生成开发文档(一)

前言对于开发人员而言,文档的作用不言而喻。文档不仅可以提高软件开发效率,还能便于以后的软件开发、使用和维护。本文主要讲述Objective-C快速生成开发文档工具appledoc。简介apple...

macOS下配置VS Code C++开发环境

本文介绍在苹果macOS操作系统下,配置VisualStudioCode的C/C++开发环境的过程,本环境使用Clang/LLVM编译器和调试器。一、前置条件本文默认前置条件是,您的开发设备已...