美文网首页
什么是跨域?

什么是跨域?

作者: 我是Msorry | 来源:发表于2021-01-01 14:43 被阅读0次

什么是同源策略

只有协议、域名、端口三者完全相同的页面才能请求数据,否者会被浏览器阻止

浏览器规定:

如果 JS 运行在 源A里,那么就只能获取源A的数据,不能获取源B的数据,既不允许跨域,这样能保护用户隐私

  • 为什么 a.qq.com 访问 qq.com也算跨域?
    答:因为历史上出现过不同公司共用域名

  • 为什么不同端口也算跨域?
    原因同上,一个端口一个公司

  • 为什么两个网站的IP是一样的,也算跨域?
    原因同上,IP可以共用

  • 为什么可以跨域使用CSS、JS和图片等?
    同源策略限制的是数据访问,我们引用 CSS、JS和图片的时候,其实并不知道内容,我们只是在引用。

同源策略限制:

  1. Cookie、LocalStorage 和 IndexDB 无法读取
  2. AJAX 请求不能发送

什么是跨域

一个域的页面去请求另一个域的数据,域名和端口都相同,但是请求路径不同,不属于跨域

CORS 跨域资源共享

对于前端开发者来说,CORS 通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
实现CORS通信的关键是服务器(后端)。只要服务器实现了CORS接口,就可以跨源通信。

前端 AJAX 代码
var request = new XMLHttpRequest(); // 新建XMLHttpRequest对象

request.onreadystatechange = function () { // 状态发生变化时,函数被回调
  if (request.readyState === 4) { // 成功完成
    // 判断响应结果:
    if (request.status === 200) {
      // 成功,通过responseText拿到响应的文本:
      return success(request.responseText);
    } else {
      // 失败,根据响应码判断失败原因:
      return fail(request.status);
    }
  } else {
    // HTTP请求还在继续...
  }
}

// 发送请求:
request.open('GET', '/api/categories');
request.send();

后端服务器代码

添加响应头Access-Control-Allow-Origin给信任的网址

var http = require('http')
var server = http.creareSever()
server.on('request',(request,response)=>{
    response.setHeader('Access-Control-Allow-Origin', url)
})

JSONP 跨域

实现原理:动态加载js,任何网站都能请求js文件,script标签的src属性不受跨域影响,可以访问外部脚本文件

IE 不支持 CORS,但是必须要有一种方式跨域。当前网站创造一个script去请求另一个网站的js,js中夹带数据;这个js文件会在当前网站执行一个回调全局函数,回调里面就有我们的数据。回调的名字是可以随机生成的一个随机数,把这个名字以callback的形式传给后台,后台会把这个函数返回过来并执行。
优点:JSONP的优点是兼容IE,可以跨域,即使请求另外的域名,也能跨域
缺点:因为是script标签,它只能知道成功和失败,拿不到状态码,header;因为是script标签,只能发get请求,不支持post

实现过程

请求方——浏览器
响应方——服务器

  1. 请求方创建scriptsrc指向响应方,同时传递查询参数?callback=random
  2. 响应方根据查询参数callback构造random.call(null,'data')这样的响应
  3. 浏览器接收响应,就会执行random.call(null,'data')
  4. 请求方得到数据

标准写法

虽然写的是ajax,但是一点关系没有,是动态的script

$.ajax({
    url: "https://ryan.com",
 
    // The name of the callback parameter, as specified by the YQL service
    jsonp: "callback",
 
    // Tell jQuery we're expecting JSONP
    dataType: "jsonp",
 
    // Tell YQL what we want and that we want JSON
    data: {
        q: "select title,abstract,url from search.news where query=\"cat\"",
        format: "json"
    },
 
    // Work with the response
    success: function( response ) {
        console.log( response ); // server response
    }
});

手写JSONP

function jsonp(url){
  return new Promise((resolve,reject)=>{
    const random = 'ryanJSONPCallbackName' + Math.random()
    //拿到数据后调用resolve
    window[random] = (data)=>{resolve(data)}
    const script = document.createElement('script')
    script.src=`${url}?callback=${random}`
    script.onload=()=>{
      script.remove()
    }
    //出错调用reject
    script.onerror =()=>{
      reject()
    }
    document.body.appendChild(script)
  })
}

Websocket

WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,能更好的节省服务器资源和带宽并达到实时通讯的目的,是server push技术的一种很好的实现。
socket本质上是对 TCP/IP 的运用进行了一层封装,应用程序直接调用 socket API 即可进行通信。
socket是如何工作的呢?
分为 2 个部分,服务端需要建立 socket 来监听指定的地址,然后等待客户端来连接。而客户端则需要建立 socket 并与服务端的 socket 地址进行连接。

WebSocket 和 HTTP最大不同是
  • WebSocket是一种双向通信协议。在建立连接后,WebSocket服务器端和客户端都能主动向对方发送或接收数据,
  • WebSocket需要像TCP一样,先建立连接,连接成功后才能相互通信。
  • 一旦WebSocket连接建立后,后续数据都以帧序列的形式传输。
  • 在客户端断开WebSocket连接或Server端中断连接前,不需要客户端和服务端重新发起连接请求。
  • 在海量并发及客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势,且客户端发送和接受消息是在同一个持久连接上发起,实时性优势明显。

websocket的基本用法

// WebSocket 协议的 URL 使用 ws://开头,另外安全的 WebSocket 协议使用 wss://开头
// 只需要实例化 WebSocket,创建连接,然后服务端和客户端就可以相互发送和响应消息
var socket = new websocket('ws://echo.websocket.org');
//当 Browser 和 WebSocketServer 连接成功后,会触发 onopen
ws.onopen = function(){ws.send(“Test!”); }; 
// 如果连接失败,发送、接收数据失败或者处理数据出现错误,会触发 onerror 
ws.onerror = function(evt){console.log(“WebSocketError!”);};
// 当 Browser 接收到 WebSocketServer 发送过来的数据时,就会触发 onmessage 消息,参数 evt 中包含 Server 传输过来的数据
ws.onmessage = function(evt){console.log(evt.data);ws.close();}; 
// 如果你想往后端推送数据,可以使用
// 因为Web Socket只能接受和发送纯为本数据,所以对数稍微复杂的数据,可以把他转化为JSON字符串
ws.send(data);
// 当 Browser 接收到 WebSocketServer 端发送的关闭连接请求时,就会触发 onclose 消息。
ws.onclose = function(evt){console.log(“WebSocketClosed!”);}; 


postMessage

postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下三个场景的跨域数据传递:

  • 页面和其打开的新窗口的数据传递
  • 多窗口之间消息传递
  • 页面与嵌套的iframe消息传递

postMessage的API

otherWindow.postMessage(message, targetOrigin, [transfer]);
  • otherWindow:其他窗口的一个引用,比如iframe的contentWindow属性,执行window.open返回的窗口对象,或者是命名过的或数值索引的window.frames。
  • message: 要发送到其他窗口的数据, html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
  • targetOrigin: 协议+主机+端口号,通过窗口的origin属性来指定哪些窗口能接收到消息事件,指定后只有对应origin下的窗口才可以接收到消息,设置为通配符"*"表示可以发送到任何窗口,但通常处于安全性考虑不建议这么做.如果想要发送到与当前窗口同源的窗口,可设置为"/"
  • transfer:可选属性,是一串和message同时传递的Transferable对象,这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。

其他窗口可以监听message事件

window.addEventListener("message", receiveMessage, false);

function receiveMessage(event)
{
  // For Chrome, the origin property is in the event.originalEvent
  // object. 
  // 这里不准确,chrome没有这个属性
  // var origin = event.origin || event.originalEvent.origin; 
  var origin = event.origin
  if (origin !== "http://example.org:8080")
    return;

  // ...
}

postMessage的具体使用示例

例如:A页面要给B页面发送消息

// A页面的域名是http://www.examplea.com:8080,在A页面的script标签下加入以下代码
const winpopup = window.open('http://www.exampleb.com:8888/b.html');
// 将第二个参数targetOrigin设置为要打开的B的域名,如果设置的和要打开的页面域名不一致,会导致消息发送不出去。
winpopup.postMessage('Hello B, I am A', 'http://www.examplea.com:8080');
function receiveMessage(event) {
    const origin = event.origin;
    // 判断信息来源是否为B
    if(origin !== "http://www.examplea.com:8080") {
        return;
    }
    // data: 从其他 window 中传递过来的对象。
    // do something
    consoel.log(event.data);
}
window.addEventListener('message', receiveMessage, false);
// B页面的域名是http://www.exampleb.com:8888,在B页面的script标签中加入以下代码

//当A页面postMessage被调用后,这个function被addEventListener调用
function receiveMessage(event)
{
  // event.origin是调用 postMessage  时消息发送方窗口的 origin, 即A页面
  // 判断信息来源是否为A
  if (event.origin !== "http://www.examplea.com:8080") {
    return;
  }
  // event.source 就当前弹出页的来源页面
  // event.data 是 "Hello B, I am A"
  // 假设你已经验证了所收到信息的origin, 可以把event.source 作为回信的对象,并且把event.origin作为targetOrigin
  event.source.postMessage("hi A! the secret response is: rheeeeet!", event.origin);
}

window.addEventListener("message", receiveMessage, false);

postMessage的使用注意事项

  • 如果您不希望从其他网站接收message,请不要为message事件添加任何事件侦听器。 这是一个完全万无一失的方式来避免安全问题。
  • 如果您确实希望从其他网站接收message,请始终使用origin和source属性验证发件人的身份。这不能低估:无法检查origin和source属性会导致跨站点脚本攻击。
  • 当您使用postMessage将数据发送到其他窗口时,始终指定精确的目标origin,而不是*。

参考:https://juejin.cn/post/6847902216049836039#heading-19

相关文章

  • 跨域问题总结

    跨域, 为什么需要跨域?跨域有什么不好?怎么实现跨域? 一、什么是跨域 只要协议、域名、端口有任何一个不同,都被当...

  • 跨域问题总结

    跨域, 为什么需要跨域?跨域有什么不好?怎么实现跨域? 一、什么是跨域 只要协议、域名、端口有任何一个不同,都被当...

  • web跨域解决方案

    围绕以下几点介绍: 什么是跨域? 常用的几种跨域处理方法? crossdomain.xml解决跨域问题 什么是跨域...

  • 跨域

    什么是跨域?怎么解决跨域问题?

  • 跨域解决方案

    在讲解决跨域解决方案之前,我们需要了解什么是跨域,在什么情况下会跨域,跨域解决的是什么问题? 一、跨域,是指浏览器...

  • 跨域

    跨域资源共享 CORS 详解什么是跨域及怎么解决跨域问题?

  • 跨域

    跨域 什么是跨域: 解决跨域 通过jsonp原理:在页面引入跨域js和css时,没有存在跨域问题.因此可以动态创建...

  • SSM框架配置CORS跨域

    什么是跨域? 跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。 常见的跨域场景: 跨域资...

  • 浏览器跨域的那些事

    整理中 目标: 了解跨域 解决跨域 服务器配置跨域(java, nginx) 前端调试时配置解决跨域 一、什么是跨...

  • 跨域问题

    前后端数据交互经常会碰到请求跨域,什么是跨域,以及有哪几种跨域方式,这是本文要探讨的内容。 一、什么是跨域? 广义...

网友评论

      本文标题:什么是跨域?

      本文链接:https://www.haomeiwen.com/subject/uhbfoktx.html