高级程序设计——跨域技术

来源:互联网 发布:淘宝详情页可以修改吗 编辑:程序博客网 时间:2024/06/05 04:15

  • 一跨源资源共享
    • ie对CORS的实现
    • 其他浏览器对CORS的实现
    • Preflighted Requests
    • 带凭据的请求
    • 跨浏览器的CORS
  • 二其他跨域技术
    • 图像Ping
    • JSONP
    • Comet
    • 服务器发送事件
      • SSE API
      • 事件流
    • Web Sockets
      • Web Sockets API
      • 发送和接收数据
      • 其他事件
  • 三安全

一、跨源资源共享

  1. 默认情况下,xhr对象只能访问与包含它的页面位于同一个域中的资源。

  2. CORS思想:使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或者响应是应该成功,还是应该失败。

ie对CORS的实现

  1. XDR对象,与xhr类似,但能实现安全可靠的跨域通信

  2. xdr与xhr的不同之处:

    • cookie不会随请求发送,也不会随响应返回
    • 只能设置请求头部信息中的Content-Type字段
    • 不能访问响应头部信息
    • 只支持GET和POST请求
  3. 被请求的资源可以根据它认为合适的任意数据(用户代理、来源页面等)来决定是否设置了Access-Control-Allow-Origin头部.作为请求的一部分,Origin头部的值表示请求的来源域,以便远程资源明确地识别XDR请求

  4. 使用方法:

    • 创建XDomainRequest实例
    • open():参数只有请求的类型和url,因为所有的xdr请求都是异步的
    • send()
    var xdr=new XDomainRequest();xdr.onload=function(){    alert(xdr.responseText);}xdr.open("get","http://www.somewhere-else.com/page/");xdr.send(null);
  5. 在接收到响应后,只能访问响应的原始文本;没有办法确定响应的状态代码

  6. 只要响应有效就会触发load事件,如果失败,就会触发error事件,但是只能知道失败了,得不到其他失败信息。

  7. 在请求返回前调用abort()方法可以终止请求

  8. 也支持timeout属性和ontimeout事件处理程序

  9. 为支持POST请求,xdr对象提供了contentType属性,用来表示发送数据的格式。这个属性是通过xdr对象影响头部信息的唯一方式

    xdr.open("post","http://www.somewhere-else.com/page/");xdr.contentType="application/x-www-form-urlencoded";xdr.send("name1=value1&name2=value2");

其他浏览器对CORS的实现

  1. 要请求位于另一个域中的资源,使用标准的XHR对象并在open()方法中传入绝对url即可

  2. 可以访问status和statusText属性,而且支持同步请求

  3. 跨域xhr对象的限制
    • 不能使用setRequestHeader()设置自定义头部
    • 不能发送和接收cookie
    • 调用getAllResponseHeaders()方法总会返回空字符串
  4. 由于无论同源请求还是跨源请求都使用相同的接口,因此对于本地资源,最好使用相对url,在访问远程资源时再使用绝对url

Preflighted Requests

  1. 通过此验证机制支持开发人员使用自定义的头部、GET或POST之外的方法,以及不同类型的主体内容。在使用下列高级选项来发送请求时,就会向服务器发送一个Preflight请求。这种请求使用OPTIONS方法,发送下列头部
    • Origin:与简单的请求相同
    • Access-Control-Request-Method:请求自身使用的方法
    • Access-Control-Request-Headers:(可选)自定义的头部信息,多个头部以逗号分隔
  2. 发送上述请求后,服务器可以决定是否允许这种类型的请求。服务器通过在响应中发送如下头部与浏览器进行沟通
    • Access-Control-Allow-Origin:与简单的请求相同
    • Access-Control-Allow-Methods:允许的方法,多个方法以逗号分隔
    • Access-Control-Allow-Headers:允许的头部,多个头部以逗号分隔
    • Access-Control-Max-Age:应该将这个Preflight请求缓存多长时间(秒)
  3. Preflight请求结束后,结果将按照响应中指定的时间缓存起来。而为此付出的代价只是第一次发送这种请求时会多一次HTTP请求

带凭据的请求

  1. 默认情况下,跨源请求不提供凭据(cookie、http认证及客户端ssl证明等)

  2. 将withCredentials属性设置为true,可以指定某个请求应该发送凭据

  3. 如果服务器接受带凭据的请求,会用下面的HTTP头部来响应
    Access-Control-Allow-Credentials:true

  4. 如果发送的是带凭据的请求,但服务器的响应中没有包含这个头部,那么浏览器就不会把响应交给JavaScript。

  5. 服务器可以在Preflight响应中发送这个HTTP头部,表示允许源发送带凭据的请求

跨浏览器的CORS

  1. 检测xhr是否支持CORS的最简单方式,就是检查是否存在withCredentials属性。再结合检测XDomainRequest对象是否存在,就可以兼顾所有浏览器了

  2. xhr和xdr共有的属性/方法:

    • abort()
    • onerror
    • onload
    • responseText
    • send()

二、其他跨域技术

  1. 利用DOM中能够执行跨域请求的功能,不依赖xhr,也能发送某种请求

  2. 不需要修改服务器端代码

图像Ping

  1. 使用<img>标签。动态地创建图像,使用他们的onload和onerror事件处理程序来确定是否接收到了响应

  2. 是与服务器进行简单、单向的跨域通信的一种方式。

  3. 请求的数据是通过查询字符串形式发送的,而响应可以是任意内容,但通常是像素图或204响应

  4. 最常用于跟踪用户点击页面或动态广告曝光次数

    var img=new Image();img.onload-img.onerror=function(){    alert("Done!");};img.src="http://www.example.com/test?name=mary";
  5. 缺点:
    • 只能发送GET请求
    • 无法访问服务器的响应文本

JSONP

  1. JSONP是JSON with padding的简写,是应用JSON的一种新方法,是包含在函数调用中的JSON。
    callback({"name":"mary"});

  2. 由 回调函数和数据 组成

    • 回调函数:当响应到来时应该在页面中调用的函数,函数的名字一般是在请求中指定的
    • 数据:传入回调函数中的JSON数据
  3. JSONP是通过动态<script>元素来使用的,使用时可以为src属性指定一个跨域url。与<img>元素类似,都有能力不受限制地从其他域加载资源。

  4. 在请求完成后,即在JSONP响应加载到页面中以后,就会立即执行

    function handleResponse(response){    alert("you are at ip address "+response.ip+" ,which is in "+response.city+", "+response.region_name);}var script=document.createElement("script");script.src="http://freegeoip.net/json/?callback=handleResponse";document.body.insertBefore(script,document.body.firstChild);
  5. 可以直接访问响应文本,支持在浏览器与服务器之间双向通信
  6. 不足:
    • 在使用不是你自己运维的web服务时,一定得保证它安全可靠
    • 要确定JSONP请求是否失败并不容易,还没有任何浏览器支持<script>的onerror事件处理程序

Comet

  1. Ajax是一种从页面向服务器请求数据的技术,而Comet则是一种服务器向页面推送数据的技术,能够让信息近乎实时地被推送到页面上,非常适合处理体育比赛的分数和股票报价

  2. 两种实现Comet的方式:

    • 长轮询
  3. 长轮询是传统轮询(短轮询)的翻版。页面发起一个到服务器的请求,然后服务器一直保持连接打开,直到有数据可发送。发送完数据之后,浏览器关闭连接,随即又发起一个到服务器的新请求。这一过程在页面打开期间一直持续不断

  4. 无论长还是短,浏览器在接收数据之前,都要先发起对服务器的连接;区别是:短轮询是服务器立即发送响应,无论数据是否有效,而长轮询是等待发送响应

  5. HTTP流,在页面的整个生命周期内只使用一个HTTP连接。就是浏览器向服务器发送一个请求,而服务器保持连接打开,然后周期性地向浏览器发送数据。

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

  7. 在firefox、safari、opera、chrome中,通过侦听readystatechange事件及检测readyState值是否为3,就可以利用xhr对象实现HTTP流。随着不断从服务器接收数据,readyState的值会周期性地变为3.当readyState值变为3时,responseText属性就会保存接收到的所有数据

    function create(url,progress,finished){    var xhr=new XMLHttpRequest(),recevied=0;    xhr.open("get",url,true);    xhr.onreadystatechange=function(){        var result;        if(xhr.readyState==3){            //只取得最新数据,substring方法提取对象中从参数开始的值            result=xhr.responseText.substring(recevied);            //调整计数器            recevied+=result.length;            progress(result);        }        else if(zhr.readyState==4){            finished(xhr.responseText);        }    };    zhr.send(null);    return xhr;}var client=create("streaming.php",function(data){    alert("recived: "+data);},function(data){    alert("Done");});

服务器发送事件

  1. SSE是围绕**只读**Comet交互推出的API或者模式。用于创建到服务器的单向连接,服务器通过这个连接可以发送任意多的数据。

  2. 服务器响应的MIME类型必须是text/event-stream,而且是浏览器中的JavaScript API能解析格式输出。

  3. SSE支持短轮询、长轮询、HTTP流,而且能在断开连接时自动确定何时重新连接

SSE API

  1. 创建一个新的EventSource对象,并传入一个入口点。传入的url必须与创建对象的页面同源(相同的url模式、域及其端口)
  2. 实例有一个readyState属性
    • 0:正连接到服务器
    • 1:打开了连接
    • 2:关闭了连接
  3. 有三个事件
    • open:在建立连接时触发
    • message:在从服务器接收到新事件时触发
    • error:在无法建立连接时触发
  4. 服务器发回的数据以字符串形式保存在event.data中

  5. 该对象会保持与服务器的活动连接。如果连接断开,还会重新连接。证明sse适合长轮询和HTTP流

  6. 立即断开连接而且不再重新连接,调用close()

事件流

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

  2. 对于多个连续的以data:开头的数据行,将作为多端数据解析,每个值之间以一个换行符分隔。只有在包含data:的数据行后面有空行时,才会触发message事件

  3. 通过id:前缀可以给特定的事件指定一个关联的id,位于data:行之前之后都可以。设置了id后,EventSource对象会跟踪上一次触发的事件。如果连接断开,会向服务器发送一个包含名为Last-Event-ID的特殊HTTP头部的请求,以便服务器知道下一次该触发哪个事件

    data:fooid:1data:bardata:foodata:bar

Web Sockets

  1. 在一个单独的持久连接上提供全双工、双向通信

  2. 在JavaScript中创建了Web Sockets之后,会有一个HTTP请求发送到浏览器以发起连接。在取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为Web Sokets协议。也就是说,使用标准的HTTP服务器无法实现Web Sokets,只有支持这种协议的专门服务器才能正常工作

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

Web Sockets API

  1. 实例化一个WebSocket对象并传入要连接的url(必须绝对url)。可以通过它打开到任何站点的连接。

  2. 表示当前状态的readyState属性,永远从0开始

    • WebSocket.OPENING(0):正在建立连接
    • WebSocket.OPEN(1):已经建立连接
    • WebSocket.CLOSING(2):正在关闭连接
    • WebSocket.CLOSE(3):已经关闭连接
  3. 没有readystatechange事件
  4. 关闭Web Socket连接,调用close(),之后readyState的值变为2,之后变为3

发送和接收数据

  1. 向服务器发送数据:send(),传入任意字符串。因为Web Sockets只能通过连接发送纯文本数据,所以对于复杂的数据结构,在通过连接发送之前,必须进行序列化

    var socket=new WebSocket("ws://www.example.com/server.php");socket.send("hello");var message={    time:new Date(),    text:"hello",    clientId:"asd"};socket.send(JSON.stringify(message));
  2. 当服务器向客户端发来消息时,WebSoket对象就会触发message事件,这个事件把返回的数据保存在event.data属性中,数据是字符串

其他事件

  1. 在连接生命周期的不同阶段触发

    • open:在成功建立连接时触发
    • error:在发送错误时触发,连接不能持续
    • close:在连接关闭时触发
  2. 不支持DOM2级事件侦听器,因此必须使用DOM0级语法分别定义每个事件处理程序

三、安全

  1. 对于未被授权系统有权访问某个资源的情况,称之为:CSRF

  2. 验证发送请求者是否有权访问相应的资源

    • 要求以ssl连接来访问可以通过XHR请求的资源
    • 要求每一次请求都要附带经过相应算法计算得到的验证码
原创粉丝点击