天天看点

跨域监听 iframe src_跨域的几种实现方式|精选博客使用降域实现跨域

一、背景

同源策略

同源策略可以理解为浏览器的一种安全机制,浏览器只允许与本域下的接口进行交互。不同源的客户端在没有明确授权的情况下,不能读写服务端的资源。

什么是不同源呢:

  • 不同的协议 例:http/https
  • 不同的域名
  • 不同的端口
  • 不同的二级域名 例:http://a.baidu.com、http://b.baidu.com(不然哪来的降域呢)

补充点

在出现跨域问题时,浏览器究竟在哪一步进行了拦截?客户端请求时?服务器不做出响应?还是服务器响应后浏览器拒绝的响应??

跨域监听 iframe src_跨域的几种实现方式|精选博客使用降域实现跨域

image.png

跨域监听 iframe src_跨域的几种实现方式|精选博客使用降域实现跨域

image.png

测试发现,在客户端和服务端不同源的情况下,服务端其实是有响应的,在此时是浏览器的同源策略拒绝了响应,认为这样不安全。

二、解决跨域问题

1. JSONP(JSON with Padding)

  • 原理: 在HTML中用script标签在加载其他域下的js,那么JSON就是利用这一特性来请求服务端,从而避免了ajax请求出现的跨域问题
  • 具体实施

(1) 定义数据处理函数_fun

(2) 创建script标签,并添加src地址来请求服务端接口,在src尾端加上自定义参数callback=_fun

(3) 服务端收到请求后,根据get参数判断返回拼接的字符串:'_fun(data)'

(4) fun(data)会放到script标签作为js执行,那么此时就会调用fun函数,将data作为函数的参数

  • 相应代码

客户端:

获取天气

function weather(data){

console.log(data)

}

document.querySelector('.btn').addEventListener('click', function(){

var script = document.createElement('script')

script.src = 'http://localhost:8080/getWeather?callback=weather&a=b'

document.head.appendChild(script)

document.head.removeChild(script)

})

服务端:

'/getWeather':function(req, resp){

resp.writeHead(200, 'success')

if(req.query.callback){

var res = JSON.stringify({'beijing':'sunny'})

resp.end(req.query.callback+'('+res+')')

}else{

resp.end(JSON.stringify({'beijing':'rain'}))

}

}

2. CORS(Cross-Origin Resource Sharing)跨域资源共享

CORS,跨域资源共享,是一种ajax跨域请求资源的方式。(几乎所有浏览器都支持,但是ie必须10以上。)

(1) 当客户端使用XMLHttpRequest发送请求时,浏览器发现请求不符合同源策略,会加上一个请求头:origin;

获取天气

document.querySelector('.btn').addEventListener('click', function(){

var xhr = new XMLHttpRequest()

xhr.open('get', 'http://www.b.com:8080/getWeather', true)

xhr.onload = function(){

console.log(xhr.responseText)

}

xhr.send()

})

跨域监听 iframe src_跨域的几种实现方式|精选博客使用降域实现跨域

image.png

(2) 在服务端收到请求并响应时,设置在响应结果加上Access-Control-Allow-Origin;

'/getWeather':function(req, resp){

resp.setHeader('Access-Control-Allow-Origin','http://www.a.com:8080')

resp.writeHead(200, 'success')

resp.end(JSON.stringify({'beijing':'rain'}))

}

跨域监听 iframe src_跨域的几种实现方式|精选博客使用降域实现跨域

image.png

或者response.setHeader('Access-Control-Allow-Origin',''),‘’代表接收所有地址的请求。

(3) 此时浏览器判断如果该响应头包含请求头origin的值,就接收响应,否则拒绝就拿不到响应数据。

CORS与JSONP区别:

  1. CORS与JSONP的使用目的相同,但是比JSONP更强大;
  2. JSONP只支持GET请求,CORS支持所有类型的HTTP请求;
  3. JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。

3. 降域

会发现当页面嵌入iframe的时候,在不同源的二级域名情况下我们是不能通过js操作iframe里面的内容的,这时可以通过降域达到目的。

使用降域实现跨域

//URL: http://a.test.com:8080/a.html

document.querySelector('.main input').addEventListener('input', function(){

console.log(this.value);

window.frames[0].document.querySelector('input').value = this.value;

})

document.domain = "test.com"

4. postMassage

在某些情况下iframe里面的服务端是愿意提供一些接口的,这时就用到了

postMessage(),postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。

//URL:http://www.a.com:8080/a.html

window.frames[0].postMessage(data,'*')

//URL:http://www.b.com:8080/b.html

window.addEventListener('message',function(e){

console.log(e.data)

})

5. 服务端中转跨域

如果对方服务器不提供跨域支持怎么办呢?这是可以自己搭建server请求中转(在服务端不存在同源策略限制)。

现在我有一个天气预报页面http://www.a.com,需要向http://www.weather.com接口获取天气数据,但是这个接口不支持JSONP和CORS跨域,那么可以这样做:

  1. 搭建服务器,创建一个获取天气的接口http://www.b.com
  2. 设置接口http://www.b.com的响应头Access-Control-Allow-Origin:http://www.a.com
  3. 页面http://www.a.com向http://www.b.com发请求
  4. http://www.b.com收到请求后,向http://www.weather.com获取天气数据,然后将天气数据返回给http://www.a.com