导读

作为一名前端开发工程师,想必对“跨域”、“”问题并不陌生,有些小伙伴甚至可能被这些问题经常折磨,久无良策。对于创业型、小型企业来说可能还未沉淀出来一套行之有效的方案,本文旨在针对工作中遇到的跨域、操作等问题上,分享在不同业务场景下的解决方案,掌握其原理,遇到类似的问题才能迎刃而解。

跨域场景

首先,先来看一段熟悉的代码片段。

<html><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>browser-safe-sandbox</title></head><body> <div>browser-safe-sandbox</div> <script>   console.log('浏览器安全沙箱')   const xhr = new XMLHttpRequest()   xhr.open('get','http://localhost:8090')   xhr.send()</script></body></html>

运行代码,打开浏览器发现如下报错:

操作过程:

前端本地服务:5500在浏览器环境中,请求本地服务端:8090接口数据,控制台报错,请求失败。

报错分解:

1. CORS策略是什么?

2. Allow 又是什么?

得出结论:

浏览器反馈的意思是,CORS策略已阻止对的访问:请求的资源上不存在“ Allow ”头,用大白话翻译过来就是“跨域”了。

为什么会跨域?

01

浏览器同源策略

所谓“同源策略”指的是三个相同,协议相同、域名相同、端口相同,下图举例说明,默认端口80。

浏览器的职责是渲染、css、等资源,从而展示成一个完整的可供浏览的网页,但是这些资源可能来自不同地方,比如本地存储前端跨域解决方案,远程服务器请求,而浏览器作为互联网主要,甚至是唯一的入口,设想一下,假如用户在A网址下登录以后,A网站在本地存储了一些隐私信息(比如银行卡号、身份证、电话等),过了一会,用户又去浏览B网站,如果没有同源限制,B网站可以读取A网站的隐私信息,更甚者,如果用户没有及时退出A网站登录,会被其他网站模仿冒充,对用户造成不可估量的损失。

由此可见,同源策略尤为重要,而且是必须的,要不然互联网就毫无安全可言,任何人,任何组织都可在互联网内为所欲为了。

小结:同源策略是浏览器安全的基石,开头的报错信息就是因为不同域的资源调用,浏览器做出拒绝访问的反馈,也就是说禁止两个不同的域之间互相访问资源。

02

浏览器同源限制

随着互联网的高速发展,现代浏览器出于用户安全保护,同源策略越来越严格,以下是非同源限制的三种行为。

1. 、 和 ,非同源,不可读写。

2. 网页资源,比如DOM,非同源,不可接触。

3. 发送AJAX请求,非同源,浏览器拒绝响应。

虽然浏览器的同源策略是必须的,但是有时候一些合理的操作也会变得很不方便,浏览器自身可以发起跨域请求,比如原生的a标签、img标签、form表单、标签等,多少有点捉襟见肘,太过局限。

其中在不同的业务场景下,上述提到的第1和3点,日常开发中使用频次是很高的,因此跨域问题必须解决,而且刻不容缓。

是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。 使基于无状态的HTTP协议记录稳定的状态信息成为了可能。

下面通过一个案例来分析共享的问题,比较具象化。

案例:

有5个一级域名相同的网站,共有5套登录系统,随着系统的不断迭代,维护成本变的越来越高,假如你是一个运营人员,每天都要操作这5个系统,5个账号,来回切换,然后把一个运营人员换成20个,这个工作量会陡然上升。

需求:

5个系统实行账号一体化,登录信息共享。

方案设计:

点击登录:

1. 首先,封装一个公共的登录组件,然后使用嵌入到需要共享登录信息的5个系统中。

2. 其次,设置的src链接(也就是存放公共组件登录逻辑的页面地址),链接最后拼接,的作用是为了通知系统登录成功后要回跳的对应地址。

3. 然后,点击登录发送请求到账号服务端同域的二级域名下,和绑定的是同一台服务器。

4. 再然后,服务端收到请求后,同时设置登录到.和.一级域名下。

5. 最后,下的网页,携带着请求自己的服务端,web服务器根据中的携带的信息就能知道,用户是否登录,从而做到账号信息共享。

另外:这种方法只适用于 和 窗口, 和 无法通过这种方法规避同源政策,而要使用下文介绍的。

退出登录:

一定要清理掉,防止被有心之人盗用。

1. 申请一个根域相同的二级域名备用。

2. 当用户在web端退出登录时,会向发送请求,告诉它该清理.下的所有了。

3. 收到请求后,会立即给登录账号服务器发送请求,告诉它清理本域下的所有。

看到这里,是不是很费解,为什么要搞这么复杂?因为前面提到了,只有在同源下才能共享,跨域操作是拿不到任何信息的,更别说共享了。那这个头疼的跨域问题到底该如何解决呢?

跨域解决方案

01

两个不同源的网页,无法获取对方的DOM,最典型的例子就是嵌套和使用.open打开的新窗口,如果两个网页只是二级域名不同,一级域名相同的话,可以通过设置.属性,获取DOM,而对于完全不同源的网站,以下介绍一种常用的方案。

.前端跨域解决方案,这是一个伴随着HTML5引出的全新API,跨文档通信的意思,举例说明:

// 父级窗口向子级窗口发消息let win = window.open('http://a.jd.com', 'name');win.postMessage('Hello JD!', 'http://a.jd.com');
// 子级窗口向父级窗口发消息window.opener.postMessage('Hello JOY!', 'http://b.jd.com');
// 父子都可进行监听window.addEventListener('message', (event) => { console.log(event.source); // 发送窗口的消息 console.log(event.origin); // 消息去往的地址 console.log(event.data); // 消息内容},false);
// 子窗口通过event.source引入父级窗口,并发送消息window.addEventListener('message', getMessage);function getMessage(event) { event.source.postMessage('Hello JD JOY!', '*');}

02

AJAX

同源策略规定,AJAX必须请求同源资源,否则就会报错,目前有以下这三种解决方案:

1. JSONP

2.

3. CORS

03

JSONP解决跨域

废话不多说,直接上代码。

<html><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JSONP跨域请求</title></head><body> <script>   function jsonpCallback(result) {      console.log("服务端响应数据",result);   } </script> <script src="http://localhost:8090/jsonp?cb=jsonpCallback"></script></body></html>

前端方案解决跨域冲突_前端跨域解决方案_前端方案解决跨域问题

或者

$.ajax({    url: "http://localhost:8090/jsonp",   dataType: 'jsonp',    success: function (data) {     console.log("服务端响应数据",result);   }})

如上,可以看到不管是用原生发起请求还是封装好的JSONP发送请求,得到的结果都是一致的,因为底层逻辑都是利用特殊标签的src属性不跨域这一特性实现的,只不过封装好的AJAX适用程度更加全面,对回调函数做了唯一性处理,以及标签是动态生成的,代码可读性更好。

优点:兼容性好,即便是古老的IE6、7、8都可适配,而且代码简洁,清晰明了,易读。

缺点:只支持GET请求,不支持POST、PUT等请求方式,这是硬伤。再者,安全度不够高,利用回调函数的方式由浏览器执行目标函数,宿主WEB容易受到各类攻击。

场景:企业内网环境,请求接口不多、业务简单不复杂的情况下,完全可以使用JSONP。

说起,用处可不是一般的大,和HTTP一样,属于一种通信协议,但是HTTP协议有个缺陷,通信只能由客户端发起,而不一样,它是双向的,服务端和客户端可以互相传递信息,服务端可以主动推送消息给客户端,客户端也可以主动向服务端发送请求。

今天只了解不实行同源策略的这个点就可以,只要服务端支持,就可以完全通过跨源通信,使用ws://(非加密)和wss://(加密)作为协议前缀,类似于(不安全)和(安全)协议前缀一样。

浏览器发出的请求头信息:

GET /chat HTTP/1.1Host: server.jd.comUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13Origin: http://a.jd.com

:表示请求的请求源,即来自哪个域名的访问,就是因为有了这个字段,服务端可以用来判断是否可以建立通信,所以这也是不实行同源策略的原因。

服务端验证通过后,会做出如下回应:

HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=Sec-WebSocket-Protocol: chat

04

CORS解决跨域

还记得开头那个报错吗?“CORS策略已阻止对的访问:请求的资源上不存在“ Allow ”。

跨源资源共享 (CORS)(或通俗地译为跨域资源共享)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它(域,协议和端口),这样浏览器可以访问加载这些资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的"预检"请求。在预检中,浏览器发送的头中标示有HTTP方法和真实请求中会用到的头。

截至2022年,市面上的浏览器几乎都支持该功能,如果是IE浏览器的话,版本不能低于10。

CORS整个通信过程都由浏览器自动完成,对于开发者而言,CORS通信与同源的AJAX请求代码逻辑完全一样,只要服务器实现了CORS接口,浏览器就会自动携带一些附加的请求头信息,从而实现跨源通信,对用户而言是无感知的。

CORS简单请求

满足下列要求的属于简单请求

1. 请求方式为其中之一

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注