一日一练-JS 了解几种跨域技术

子曰:了解几种跨域机制

简单介绍

首先简单了解一下同源策略相关知识点:

1.同源策略 限制了从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要机制。

2.源的定义:如果两个页面的协议、端口和域名都相同,则两个页面具有相同的

3.同源策略规定,是XHR 实现Ajax 通信的一个主要限制。默认情况下,XHR 对象只能访问与包含它的页面位于同一个域中的资源。这种安全策略可以预防某些恶意行为。但是,实现合理的跨域请求对开发某些浏览器应用程序也是至关重要的。

下面是几种跨域技术。

CORS

0x00:定义

CORS(Cross-Origin Resource Sharing,跨域资源共享)是W3C 的一个工作草案,定义了在必须访问跨域资源时,浏览器与服务器应该如何沟通。CORS 背后的基本思想,就是使用自定义的HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。

比如一个简单的使用GET 或POST 发送的请求,它没有自定义的头部,而主体内容是text/plain。在发送该请求时,需要给它附加应该额外的Origin 头部,其中包含请求页面的源信息(协议、域名和端口),以便服务器根据这个头部信息来决定是否给与响应。下面是Origin 头部的应该示例:

Origin: http://www.example.com

如果服务器任务这个请求可以接受,就在Access-Control-Allow-Origin 头部中回发相同的源信息(如果是公共资源,可以回发*)。例如:

Access-Control-Allow-Origin: http://www.example.com

如果没有这个头部,或者有这个头部但源信息不匹配,浏览器就会驳回请求。正常情况下,浏览器会处理请求。注意,请求和响应都不包含cookie 信息。

0x01:现代浏览器对CORS 的实现

Webkit 内核的现代浏览器都通过XMLHttpRequest 对象实现了对CORS 的原生支持。在尝试打开不同来源的资源时,无需额外编写代码就可以触发这个行为。

var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
  if (xhr.readyState == 4) {
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
      alert(xhr.responseText)
    } else {
      alert(‘Request was unsuccessful: ‘ + xhr.status)
    }
  }
}
xhr.open(‘get‘, ‘http://www.example.com/page/‘, true)
xhr.send(null)

跨域XHR 对象有一些安全限制

1.不能使用setRequestHeader() 设置自定义头部。

2.不能发送和接收cookie

3.调用getAllResponseHeader() 方法总会返回空字符串。

0x02:Preflighted Requests(预检请求)

CORS 通过一种叫做Preflighted Requests 的透明服务器机制支持开发人员使用自定义的头部、GET 或POST 之外的方法,以及不同类型的主体内容。在使用下列高级选项发送请求时,就会向服务器发送一个Preflight 请求。这种请求使用OPTIONS 方法,发送下列头部。

1.Origin:与简单的请求相同。

2.Access-Control-Request-Method:请求自身使用的方法。

3.Access-Control-Request-Headers:(可选)自定义的头部信息,多个头部以逗号分割。

下面是一个带有自定义头部NCZ 的使用POST 发送的请求

Origin: http://www.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: NCZ

发送这个请求后,服务器可以决定是否允许这种类型的请求。服务器通过在响应中发送如下头部与浏览器进行沟通。

1.Access-Control-Allow-Origin:与简单的请求相同。

2.Access-Control-Allow-Methods:允许的方法,多个方法以逗号分隔。

3.Access-Control-Allow-Headers:允许的头部,多个头部以逗号分隔。

4.Access-Control-Max-Age:应该将这个Preflight 请求缓存多长时间(以秒表示)。

例如:

Access-Control-Allow-Origin: http://www.example.com
Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Headers: NCZ
Access-Control-Mag-Age:1728000

Preflight 请求结束后,结果将按照响应中指定的时间缓存起来。而为此付出的代价只是第一次发送这种请求时会多一次HTTP 请求。

0x03:带凭据的请求

默认情况下,跨源请求不提供凭据(cookie,HTTP 认证及客户端SSL 证明等)。通过将withCredentials 属性设置为true,可以指定某个请求应该发送凭据。如果服务器接受带凭据的请求,会用下面的HTTP 头部来响应。

Access-Contol-Allow-Credentials: true

如果发送的是带凭据的请求,但服务器的响应中没有包含这个头部,那么浏览器就不会把响应交给JavaScript(于是,responseText 中将是空字符串,status 的值为0,而且会调用onerror() 事件处理程序)。另外,服务器还可以在Preflight 响应中发送这个HTTP 头部,表示允许源发送带凭据的请求。

图像Ping

0x00:定义

图像Ping 是与服务器进行简单、单向的跨域通信的一种方式。请求的数据是通过查询字符串形式发送的,而响应可以是任意内容,但通常是像素图或204 响应。通过图像Ping,浏览器得不到任何具体的数据,但通过侦听load 和error 事件,它能知道响应是什么时候收到。

0x01:例子

var img = new Image()
img.onload = img.onerror = function () {
  alert(‘Done!‘)
}
img.src = ‘http://www.example.com/test?name=Nicholas‘

这里创建了一个Image 实例,然后将onload 和onerror 事件处理程序指定为同一个函数。这样无论是什么响应,只要请求完成,就能得到通知。请求从设置src 属性那一刻开始,而这个例子在请求中发送了一个name 参数。

0x02: 作用

图像Ping 最常用于跟踪用户点击页面或动态广告曝光次数。图像Ping 有两个主要的缺点,一是只能发送GET 请求,而是无法访问服务器的响应文本。因此,图像Ping 只能用于浏览器与服务器间的简单通信。

JSONP

0x00:定义

JSONP 是JSON with Padding(填充式JSON或参数式JSON)的简写,是应用JSON 的一种新方法。JSONP 看起来与JSON 差不多,只不过是被包含在函数调用中的JSON。

callback({"name": "Nicholas"})

JSONP 由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的JSON 数据。

0x01:例子

这是应该典型的JSONP 请求

http://freegeoio.net/json/?callback=handleResponse

这个URL 是在请求应该JSONP 地理定位服务。通过查询字符串来指定JSONP 服务的回调参数,这里指定的回调函数的名字叫handleResponse()

JSONP 是通过动态创建<script> 元素来使用的,使用时可以为src 属性指定应该跨域URL。<script> 元素和<img> 元素都有能力不受限制地从其他域加载资源。因为JSONP 是有效的JavaScript 代码,所以在请求完成后,即在JSONP 响应加载到页面中以后,就会立即执行。

function handleResponse (response) {
  alert("You‘re at IP address " + reponse.ip + ", which is in " +
    response.city + ", " + response.region_name)
}
var script = document.createElement(‘script‘)
script.src = ‘http://freegeoio.net/json/?callback=handleResponse‘
document.body.insertBefore(script, document.body.firstChild)

0x02: 作用

与图像Ping 相比,优点在于能够直接访问响应文本,支持在浏览器与服务器之间双向通信。

缺点:需要确保其他域的安全可靠,以及确定JSONP 请求是否失败并不容易。

Comet

0x00:定义

Comet 指的一种更高级的Ajax 技术(也被称为“服务器推送”)。Ajax 是一种从页面向服务器请求数据的技术,而Comet 则是一种服务器向页面推送数据的技术。Comet 能够让信息近乎实时地被推送到页面上,非常适合处理体育比赛的分数和股票报价。

0x01:实现

有两种实现Comet 的方式:长轮询和流。

1.短轮询:浏览器定时向服务器发送请求,看看有没有更新的数据。下图是短轮询的时间线

2.长轮询:页面发生器一个服务器的请求,然后服务器一直保持连接打开知道有数据可发送。发送完数据之后,浏览器关闭连接,随即由发起一个到服务器的新请求。这一过程在页

面打开期间一直保持不断。下面是长轮询的时间线

3.HTTP流:流不同于轮询,因为它在页面的整个生命周期内只使用一个HTTP 连接。具体来说,就是浏览器向服务器发送一个请求,而服务器保持连接打开,然后周期性地向浏览器发送数据。

所有服务器端语言都支持打印到输出缓存然后刷新(将输出缓存中的内容一次性全部发送到客户端)的功能。而这正是实现HTTP 流的关键所在。

在现代浏览器中,通过侦听readstatechange 事件以及检测readyState 的值是否为3,就可以利用XHR 对象实现HTTP 流。随着不断从服务器接收数据,readState 的值就会周期性地变为3。当readyState 值变为3 时,responseText 属性中会保存接收到的所有数据。

服务器发送事件

0x00:定义

SSE(Server-Sent Events,服务器发送事件)是围绕只读Comet 交互推出的API 或者模式。SSE API 用于创建到服务器的单向连接,服务器通过这个连接可以发送任意数量的数据。服务器响应的MIME 类型必须是text/event-stream,而且是浏览器中的JavaScript API能解析格式输出。

0x01: SSE API

SSE 的JavaScript API 与其他传递消息的JavaScript API 很相似。要预定新的事件流,首先要创建一个新的EventSource 对象,并传进一个入口点:

var source = new EventSource(‘myevents.php‘)

注意,传入的URL 必须与创建对象的页面同源(相同的URL 模式、域及端口)。EventSource 的实例有一个readyState 属性,值为0 表示正连接到服务器,值为1 表示打开连接,值为2 表示关闭连接。

另外,还有以下三个事件。

1.open:在建立连接时触发。

2.message:在从服务器接收到新事件时触发。

3.error:无法建立连接时触发。

onmessage 事件处理程序的使用

source.onmessage = function (event) {
  var data = event.data
  // 处理数据
}

服务器发回的数据以字符串形式保存在event.data 中。

默认情况下,EventSource 对象会保持与服务器的活动连接。如果连接断开,还会重新连接。这就意味着SSE 适合长轮询和HTTP 流。如果想强制立即断开连接并且不再重新连接,可以调用close() 方法。

source.close()

0x02:事件流

所谓的服务器事件会通过一个持久的HTTP 响应发送,这个响应的MIME 类型为text/event-stream。响应的格式是纯文本,最简单的情况是每个数据项都带有前缀data:,例如:

data: foo

data: bar

data: foo
data: bar

对以上响应而言,事件流中的第一个message 事件返回的event.data 值为foo,第二个message 事件返回的event.data 值为bar,第三个message 事件返回的event.data 值为foo\nbar(注意中间的换行符)。对于多个连续的以data: 开头的数据行,将作为多段数据解析,每个值之间以一个换行符分割。只能在包含data:的数据行后面有空行时,才会触发message 事件,因此在服务器上生成事件流时不能忘了多添加这一行。

通过id: 前缀可以给特定的事件指定一个关联的ID,这个ID 行位于data: 行前面或皆可:

data: foo
id: 1

设置了ID 后,EventSource 对象会跟踪上一次触发的事件。如果连接断开,会向服务器发送一个包含名为Last-Event-ID 的特殊HTTP 头部的请求,以便服务器知道下一次该触发哪个事件。在多次连接的事件流中,这种机制可以确保浏览器以正确的顺序收到连接的数据段。

Web Sockets

0x00:定义

Web Sockets 的目标是在一个单独的持久连接上提供全双工、双向通信。在JavaScript 中创建了Web Socket 之后,会有一个HTTP 请求发送到浏览器以发起连接。在取得服务器响应后,建立的连接会使用HTTP 升级为HTTP 协议交换为Web Socket 协议。也就是说,使用标准的HTTP 服务器无法实现Web Sockets,只有支持这种协议的专门服务器才能正常工作。

由于Web Sockets 使用了自定义的协议,所以URL 模式也略有不同。未加密的连接不再是http:// 而是ws://;加密的连接也不是https://而是wss://

使用自定义协议而非HTTP 协议的好处是,能够在客户端和服务器之间发送非常少量的数据,由于传递的数据包很小,因此Web Sockets 非常适合移动应用。

0x01:Web Sockets API

要创建Web Socket,先实例一个WebSocket 对象并传入要连接的URL:

var socket = new WebSocket(‘ws://www.example.com/server.php‘)

注意,必须给WebSocket 构造函数传入绝对URL。同源策略对Web Sockets 不适用,因此可以通过它打开到任何站点的连接。

实例化了WebSocket 对象后,浏览器就会马上尝试连接。WebSocket 也有一个表示当前状态的readyState 属性。

1.WebSocket.OPENING(0):正在建立连接。

2.WebSocket.OPEN(1):已经建立连接。

3.WebSocket.CLOSING(2):正在关闭连接。

4.WebSocket.CLOSE(3):已经关闭连接。

readyState 的值永远从0 开始。

要关闭Web Socket 连接,可以在任何时候调用close() 方法。

socket.close()

调用了close() 之后,readyState 的值立即变为2(正在关闭),而在关闭连接后就会变成3。

0x02:发送和接收数据

Web Socket 打开之后,就可以通过连接发送和接收数据。要向服务器发送数据,使用send() 方法并传入任意字符串,例如:

var socket = new WebSocket(‘ws://www.example.com/server.php‘)
socket.send(‘Hello world!‘)

因为Web Socket 只能通过连接发送纯文本数据,所以对于复杂的数据结构,在通过连接发送之前,必须进行序列化。下面的例子展示了先将数据序列化为一个JSON 字符串,然后再发送到服务器:

var message = {
  time: new Date(),
  text: ‘Hello world!‘,
  clientId: ‘asdfp‘
}
socket.send(JSON.stringify(message))

接下来,服务器要读取其中的数据,就要解析接收到的JSON 字符串。

当服务器向客户端发来消息时,WebSocket 对象就会触发message 事件。这个message 事件与其他传递消息的协议类似,也是把返回的数据保存在event.data 属性中。

socket.onmessage = function (event) {
  var data = event.data
  // 处理数据
}

与通过send() 发送到服务器的数据一样,event.data 中返回的数据也是字符串。如果你想要得到其他格式的数据,必须手动解析这些数据。

0x03:其他事件

WebSocket 对象还有其他三个事件,在建立生命周期的不同阶段触发。

1.open: 在成功建立连接时触发。

2.error: 在发生错误时触发,连接不能持续。

3.close: 在连接关闭时触发。

WebSocket 对象不支持DOM 2 级事件侦听器,因此必须使用DOM 0 级语法分别定义每个事件处理程序。

var socket = new WebSocket(‘ws://www.example.com/server.php‘)

socket.onopen = function () {
  alert(‘Connection established.‘)
}

socket.onerror = function () {
  alert(‘Connection error.‘)
}

socket.onclose = function () {
  alert(‘Connection closed.‘)
}

在这三个事件中,只有close 事件的event 对象有额外的信息。这个事件的事件对象有三个额外的属性:wasCleancodereason。其中,wasClean 是一个布尔值,表示连接是否已经明确地关闭;code 是服务器返回的数值状态码;而reason 是一个字符串,包含服务器发回的消息。可以把这些信息显示给用户,也可以记录到日志中以便将来分析。

socket.onclose = function (event) {
  console.log(‘Was clean? ‘ + event.wasClean + " Code=" + event.code + " Reason=" + event.reason)
}

原文地址:https://www.cnblogs.com/JobbyM/p/9295125.html

时间: 2024-08-25 09:20:19

一日一练-JS 了解几种跨域技术的相关文章

一日一练-JS rem布局在webview 中错乱

子曰:在实践中学习 今天测试同事说,app 中的h5 页面在Mate Pro 10 中出现错误,不能够占满全屏,只占据了90% 的宽度.这是一个大bug 啊! 开始进行了排查是否是代码问题?rem 的问题?webview 的问题?最后在网络上检索到是参考文档中的内容.这里记录了解决方案. 我们在开发hybrid 应用时,h5 页面的使用rem 进行适配,设计师给出750px 宽度的设计图,在750px 设计图上进行开发.通常在适配时,都是在<head> 标签中加载一段<script>

JS同源策略和跨域访问

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响.可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现. 1. 什么是同源策略 理解跨域首先必须要了解同源策略.同源策略是浏览器上为安全性考虑实施的非常重要的安全策略. 何谓同源: URL由协议.域名.端口和路径组成,如果两个URL的协议.域名和端口相同,则表示他们同源. 同源策略: 浏览器的同源策略,限制了来自不同源的"doc

详解5种跨域方式及其原理

同源定义 如果两个页面拥有相同的协议(protocol),端口(如果指定),和主机,那么这两个页面就属于同一个源(origin). 以下是同源检测的示例 URL 结果 原因 http://store.company.com/dir2/other.html Success http://store.company.com/dir/inner/another.html Success https://store.company.com/secure.html Failure 协议不同 http://

web三种跨域请求数据方法

web三种跨域请求数据方法 以下测试代码使用php,浏览器测试使用IE9,chrome,firefox,safari <!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.

js之Ajax与跨域

一.Ajax 我们对Ajax一定不会陌生,异步发送请求获取数据,这是我们前端与后台服务器交互的重要的手段,那么对于ajax我们需要了解什么呢? 我们手写一个ajax,这样就能够基本了解使用了ajax了. 1 var xhr = new XMLHttpRequest(); // XMLHttpRequest是ajax最重要的api 2 3 xhr.open("GET", "/admin/user"); 4 5 xhr.onreadystatechange = func

原生的js实现jsonp的跨域封装

一.原理 jsonp是利用浏览器请求script文件时不受同源策略的限制而实现的,伪造一个script标签,将请求数据的url赋值给script的src属性,并将该标签添加到html中,浏览器会自动发送请求,返回的一般时一段js代码,即函数的调用代码 该种跨域的请求方式需要后台配合返回响应的函数执行数据 二.封装代码 function jsonp (url, data, callback) { let scriptTag = document.createElement('script') le

JavaScript 九种跨域方式实现原理

前言 前后端数据交互经常会碰到请求跨域,什么是跨域,以及有哪几种跨域方式,这是本文要探讨的内容. 一.什么是跨域? 1.什么是同源策略及其限制内容? 同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到 XSS.CSFR 等***.所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个 ip 地址,也非同源.同源策略限制内容有: Cookie.LocalStorage.IndexedDB 等存储性内容DOM 节点AJAX 请求发送

九种跨域方式实现原理

前言 前后端数据交互经常会碰到请求跨域,什么是跨域,以及有哪几种跨域方式,这是本文要探讨的内容. 本文完整的源代码请猛戳github 博客 一.什么是跨域? 1.什么是同源策略及其限制内容? 同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到 XSS.CSFR 等攻击.所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个 ip 地址,也非同源. 同源策略限制内容有: Cookie.LocalStorage.IndexedDB

[转载]解决flash与js交互、flash跨域交互、flash跨域提交

http://blog.csdn.net/andyxm/article/details/5219919 我们引用本地flash,实现flash与js双向交互. function thisMovie(movieName) {     if (window.document[movieName]){      return window.document[movieName];    }else if (navigator.appName.indexOf("Microsoft")==-1)