您当前的位置: 首页 > 

顺其自然~

暂无认证

  • 0浏览

    0关注

    1317博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

同源策略、跨域解决方案

顺其自然~ 发布时间:2021-04-16 09:40:21 ,浏览量:0

一、同源策略 1、先来说说什么是源

 源(origin,起源)就是协议、域名和端口号。如某url中的源就是:http://www.company.com:80。若地址里面的协议、域名和端口号均相同则属于同源。 以下是相对于 http://www.a.com/test/index.html 的同源检测

• http://www.a.com/dir/page.html ----成功 • http://www.child.a.com/test/index.html ----失败,域名不同 • https://www.a.com/test/index.html ----失败,协议不同 • http://www.a.com:8080/test/index.html ----失败,端口号不同

2.什么是同源策略?

同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以a.com下的js脚本采用ajax读取b.com里面的文件数据是会报错的。

不受同源策略限制的: 1、页面中的链接,重定向以及表单提交是不会受到同源策略限制的。 2、跨域资源的引入是可以的。但是js不能读写加载的内容。如嵌入到页面中的,,,等。

二、跨域 1、什么是跨域

受前面所讲的浏览器同源策略的影响,不是同源的脚本不能操作其他源下面的对象。想要操作另一个源下的对象是就需要跨域。

2、跨域的实现形式

2.1、降域 document.domain 同源策略认为域和子域属于不同的域,如: child1.a.com 与 a.com, child1.a.com 与 child2.a.com, xxx.child1.a.com 与 child1.a.com 两两不同源,可以通过设置 document.damain='a.com',浏览器就会认为它们都是同一个源。想要实现以上任意两个页面之间的通信,两个页面必须都设置documen.damain='a.com'。此方式的特点:

1. 只能在父域名与子域名之间使用,且将 xxx.child1.a.com域名设置为a.com后,不能再设置成child1.a.com。 2. 存在安全性问题,当一个站点被攻击后,另一个站点会引起安全漏洞。 3. 这种方法只适用于 Cookie 和 iframe 窗口。

2.2、JSONP跨域

举例:a.com/jsonp.html想得到b.com/main.js中的数据。

在a.com的jsonp.html里创建一个回调函数xxx,动态添加元素,向服务器发送请求,请求地址后面加上查询字符串,通过callback参数指定回调函数的名字。请求地址为http://b.com/main.js?callback=xxx。在main.js中调用这个回调函数xxx,并且以JSON数据形式作为参数传递,完成回调。我们来看看代码: // a.com/jsonp.html中的代码

function addScriptTag(src) {
   var script = document.createElement('script');
   script.setAttribute("type","text/javascript");
   script.src = src;
   document.body.appendChild(script);
}
window.onload = function () {
    addScriptTag('http://b.com/main.js?callback=foo');
} //window.onload是为了让页面加载完成后再执行
function foo(data) {
   console.log(data.name+"欢迎您");
};

//b.com/main.js中的代码

foo({name:"hl"})

这样便实现了跨域的参数传递。

采用jsonp跨域也存在问题:

1. 使用这种方法,只要是个网站都可以拿到b.com里的数据,存在安全性问题。需要网站双方商议基础token的身份验证,这里不详述。 2. 只能是GET,不能POST。 3. 可能被注入恶意代码,篡改页面内容,可以采用字符串过滤来规避此问题。

2.3、CORS CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。 它允许浏览器向跨域服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。 刚才的例子中,在b.com里面添加响应头声明允许a.com的访问,代码:Access-Control-Allow-Origin: http://a.com 然后a.com就可以用ajax获取b.com里的数据了。 注意:此方法IE8以下完全不支持,IE8-10部分支持。详见caniuse-CORS 详细内容请参考:跨域资源共享 CORS 详解

2.4、 HTML5的postMessage方法

postMessage() 方法用于安全地实现跨源通信。

otherWindow.postMessage(message, targetOrigin, [transfer]);
参数说明otherWindow其他窗口的一个引用,比如 iframe 的 contentWindow 属性、执行 window.open 返回的窗口对象、或者是命名过或数值索引的 window.frames。message将要发送到其他 window的数据。targetOrigin指定哪些窗口能接收到消息事件,其值可以是 *(表示无限制)或者一个 URI。transfer可选,是一串和 message 同时传递的 Transferable 对象。这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。

浏览器支持

Chrome 1Edge 12Firefox 8Safari 4Opera 9.5

发送程序

发送消息

你的浏览器不支持 iframe。

window.onload = function() { var receiver = document.getElementById('receiver').contentWindow; var btn = document.getElementById('sendMessage'); btn.addEventListener('click', function (e) { e.preventDefault(); var val = document.getElementById('text').value; receiver.postMessage("Hello "+val+"!", "https://c.runoob.com"); }); }

接收程序:https://c.runoob.com/runoobtest/postMessage_receiver.html

接收程序有一个事件监听器,监听 "message" 事件,同时我们要验证消息来源地址,以确保是个可信的发送地址。

Hello World!
window.onload = function() { var messageEle = document.getElementById('recMessage'); window.addEventListener('message', function (e) { // 监听 message 事件 alert(e.origin); if (e.origin !== "https://www.runoob.com") { // 验证消息来源地址 return; } messageEle.innerHTML = "从"+ e.origin +"收到消息: " + e.data; }); }
  • e.source – 消息源,消息的发送窗口/iframe。
  • e.origin – 消息源的 URI(可能包含协议、域名和端口),用来验证数据源。
  • e.data – 发送过来的数据。

2.5、window.name

window.name这个属性不是一个简单的全局属性 --- 只要在一个window下,无论url怎么变化,只要设置好了window.name,那么后续就一直都不会改变,同理,在iframe中,即使url在变化,iframe中的window.name也是一个固定的值,利用这个,我们就可以实现跨域了

代码实例:

test1.html





test1


  test1页面
  
  
    var ifr = document.querySelector('iframe')
    ifr.style.display = 'none'
    var flag = 0;
    ifr.onload = function () {
        console.log('跨域获取数据', ifr.contentWindow.name);
        ifr.contentWindow.close();
    }
  

test2.html




  
  test2


  test2页面
  
    var person = {
      name: 'wayne zhu',
      age: 22,
      school: 'xjtu'
    }
    window.name = JSON.stringify(person)
  

使用浏览器访问test1.html:http://192.168.1.10/php_demo/test1.html

运行截图:

参考文献:window.name实现跨域 - Wayne-Zhu - 博客园

2.6、location.hash

前提准备: a.html,起在localhost:3000上 b.html,起在localhost:3000上 c.html,起在localhost:4000上 可见a和b是同域的,c是独立的

需求:在a页面获取c页面发送的数据。 思路:a给c传一个hash值,c收到hash值后,c把hash值传递给b,b把结果放到a的hash中 代码: a.html



   
       
   
   
       
        
         //hash一变化,就获取变化后的hash值,这个hash值就是a传给c,c得到后响应,返回给b,b传递给a的
         window.onhashchange = function(){
          console.log(location.hash);
         }
        
   

b.html



	
	   
	  
	
	   
	   
	    window.parent.parent.location.hash = location.hash;
	   
	

c.html



	
	   
	
	
	   
	    let iframe = document.createElement("iframe");
	    iframe.src = 'http://localhost:3000/b.html#18';
	    document.body.appendChild(iframe);
	   
	

现象:结果为#18原因分析: 访问a.html会加载c.html,并把值放在c的iframe的hash中, 然后c载入后,会加载b.html,并把值放在b的iframe的hash中, 而a和b是同域的,那么也就是说b的hash可以直接复制给a的hash,这样a就得到了c的值

2.7、websocket

webSocket本身不存在跨域问题,所以我们可以利用webSocket来进行非同源之间的通信。websocket如何实现跨域通信? 原理:利用webSocket的API,可以直接new一个socket实例,然后通过open方法内send要传输到后台的值,也可以利用message方法接收后台传来的数据。后台是通过new WebSocket.Server({port:3000})实例,利用message接收数据,利用send向客户端发送数据。具体看以下代码: 代码: 本地域打开socket.html

WebSocket是高级api,不兼容,但是可以使用socket.io这个库,这个库做了兼容处理

 
 
 
  
 
 
  

   
    let socket = new WebSocket("ws://localhost:3000");//ws协议是webSocket自己创造的
    socket.onopen = function(){
     socket.send("我叫俞华");
    }
    socket.onmessage = function(e){
     console.log(e.data);//你好,我叫俞华!
    }
   
 
 
  • 起一个服务端
  • 一般起的服务是http服务,但是websocket需要起ws服务,ws是webSocket自己定义的。
 /*
  要使用ws协议,那么就要装一个ws的包
 */
 let express = require("express");
 let app = express();
 let WebSocket = require("ws");
 let wss = new WebSocket.Server({port:3000});
 wss.on("connection",function(ws){//先连接
  ws.on("message",function(data){//用message来监听客户端发来的消息
   console.log(data);//俞华
   ws.send("你好,"+data+"!");
  })
 })

如何保证websocket的通信会话是唯一的?

  • 建立WebSocket链接的url上加上时间戳。
关注
打赏
1662339380
查看更多评论
立即登录/注册

微信扫码登录

0.0404s