【每日十分钟前端】浏览器1,跨域解决方案

跨域即跨域名的访问。

为何禁止跨域

由浏览器的同源策略导致的,为了防范跨站脚本的攻击,禁止客户端脚本对不同域下的文档或脚本进行跨站资源交互。
如果缺少同源策略,浏览器很容易受到XSS、CSFR等攻击。

同源

协议(http://)、域名(www.baidu.com)、端口号(:80),三者一致。

同源带来的问题

1、一级域名相同,二级域名不同的同意所有者的网页被限制;
2、无法跨域发送AJAX请求;
3、无法操作DOM。

为什么AJAX不可以跨域发送请求,而Form表单可以?

Form表单提交之后会刷新页面,所以即使跨域了也无法获取到数据,所以浏览器认为这个是安全的,而且AJAX最大的有点就是在不重新加载整个页面的情况下,更新部分页面内容,如果让他跨域,则可以读取到目标URL的私密信息,这将会变得非常危险,所以浏览器不允许AJAX发送跨域请求。

跨域报错

No 'Access-Control-Allow-Origin' header...

解决方案

1、jsonp
2、cors
3、nginx反向代理
4、node正向代理/nodejs中间件代理跨域
5、postMessage
6、websocket
7、vue中的proxyTable
8、iframe
+document.domain
+location.hash
+window.name

jsonp

Json With Padding,最早的解决方案。
动态创建script标签,利用src不受同源策略约束的性质来实现跨域获取数据。
注意:
(1)、需要服务器的支持;
(2)、只能发起get请求;
(3)、携带数据较小;
(4)、要确定jsonp请求是否失败并不容易,一般用计时器检测指定时间内是否接收到了响应。

cors

Cross-origin resource sharing,是一个W3C标准,跨域资源共享。

它允许浏览器向跨源服务器,发出XMLHttpRequest请求。

需要浏览器(IE10以下不支持)和服务器同时支持。

浏览器端:会自动完成。
服务器端:一般通过过滤器过滤浏览器携带的一些头信息(用额外的HTTP头)判断是否运行其跨域,然后在响应头中加入一些信息。来告诉浏览器让该Web应用被准许访问来自不同源服务器上的指定的资源。(服务器设置Access-Control-Origin HTTP响应头,浏览器将允许跨域请求)

nginx反向代理

利用nginx反向代理把跨域为不跨域,支持各种请求方式。

缺点:需要再nginx进行额外配置,语义不清晰。

补充:
(1)、代理:不直接去做,找第三方来。
(2)、正向代理与反向代理: 正向代理代理客户端,反向代理代理服务器。

node正向代理/nodejs中间件代理跨域

服务端请求不会跨域,让接口和当前站点同源。
由nodejs服务,做路由转发API。

缺点:上线的时候,必须启动nodejs服务。

postMessage

postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信。
postMessage(data,origin)
data:顾名思义,是传递来的message。
origin:发送消息窗口的源(协议+主机+端口号)。

WebSocket协议跨域

一种网络通信协议。
HTML5开始提供的一种在单个TCP连接上进行全双工通讯的协议。
客户端和服务器之间存在持久的连接,而且双方都可以随时开始发送数据。

起因:
HTTP协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出应答处理。
这种通信模型有一个弊端,HTTP协议无法实现服务器主动向客户端发起消息。
这种请求如果服务器有连续的状态变化,客户端会比较麻烦,大多数采用复杂的异步请求实现长轮询,轮询效率低,浪费资源。
WebSocket就是这样发明的,只要连接一次,就能一直保持连接状态。

vue中的proxyTable

vue中配置好的,设置一下就可以了。

//在config中的index.js配置:  

dev{
    proxyTable: {
        '/api': {
            target: 'www.name.com', // 要代理的域名
            changeOrigin: true,//允许跨域
            pathRewrite: {
              '^/api': '' // 要访问的路径,名字随意
            }
        }
    }
}


使用:
/api/getMenu相当于http://www.name.com/getMenu

iframe

(1)、document.domain + Iframe

仅仅适用于:主域相同、子域不同时。

运行方式:
a.name.com访问b.name.com
使用document.domain=name.com

(2)、window.location.hash + Iframe

通过url带hash,通过一个非跨域的中间页面来传递数据。
hash属性是一个可读可写的字符串,该字符串是URL的锚部分(#开始的部分)

运行方式:
A.html访问C.html的数据(两者跨域):
(B.html中间页面,与A同域)

A操作C,A通过location.hash传递参数给C,C通过定时器检测hash变化,传给中间页面B,B监听C传来的hash值,再通过操作同域A的js回调,将结果传回。

//A.html

iframe.src="http://www.name.com/C.html"
iframe.onload = function() {
    // 传递数据:age = 18;
	iframe.src = "http://www.name.com/C.html#age=18";
}
function response(res) {
	alert(res);
}



//C.html
window.onhashchange = function () {
	iframe.src = "http://www.name.com/C.html" + location.hash;
}
	
	

//B.html
window.onhashchange = function () {
	// => 再通过操作同域A的js回调,将结果传回
	window.parent.parent.response(location.hash);
};

1)、动态改变location.hash,iframe不会重载;
2)、无论跨域与否,iframe内可以获取自己的location.hash;
3)、只要域名相同就能通信,即使ABC三层嵌套。

location.hash缺点:
1)、传递数据量有限;
2)、不太安全。

(3)、window.name + Iframe

window.name利用在一个浏览器窗口内,载入所有的域名都是共享一个window.name,当该 window 的 location 变化,然后重新加载,它的 name 属性可以依然保持不变。

运行方式:
A.html访问C.html的数据(两者跨域):
(B为空的中间页面,与A同域)

加载两次,第一次加载跨域页面,并保留数据于window.name,切换到B.htmliframe.src = "http://www.name.com/B.html"
第二次(B.html)加载成功后,读取同域名下的window.name中数据

// A.html:
iframe.src="http://www.name.com/C.html"

let first = true;
iframe.onload = () => {
    if (first) {
      iframe.src = "http://www.name.com/B.html";
      first = false;
    } else {
      console.log(iframe.contentWindow.name);
    }
}

//B.html
<div></div>

//C.html
window.name="xxx"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值