高级程序设计——跨域技术
来源:互联网 发布:淘宝详情页可以修改吗 编辑:程序博客网 时间:2024/06/05 04:15
- 一跨源资源共享
- ie对CORS的实现
- 其他浏览器对CORS的实现
- Preflighted Requests
- 带凭据的请求
- 跨浏览器的CORS
- 二其他跨域技术
- 图像Ping
- JSONP
- Comet
- 服务器发送事件
- SSE API
- 事件流
- Web Sockets
- Web Sockets API
- 发送和接收数据
- 其他事件
- 三安全
一、跨源资源共享
默认情况下,xhr对象只能访问与包含它的页面位于同一个域中的资源。
CORS思想:使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或者响应是应该成功,还是应该失败。
ie对CORS的实现
XDR对象,与xhr类似,但能实现安全可靠的跨域通信
xdr与xhr的不同之处:
- cookie不会随请求发送,也不会随响应返回
- 只能设置请求头部信息中的Content-Type字段
- 不能访问响应头部信息
- 只支持GET和POST请求
被请求的资源可以根据它认为合适的任意数据(用户代理、来源页面等)来决定是否设置了Access-Control-Allow-Origin头部.作为请求的一部分,Origin头部的值表示请求的来源域,以便远程资源明确地识别XDR请求
使用方法:
- 创建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);
在接收到响应后,只能访问响应的原始文本;没有办法确定响应的状态代码
只要响应有效就会触发load事件,如果失败,就会触发error事件,但是只能知道失败了,得不到其他失败信息。
在请求返回前调用abort()方法可以终止请求
也支持timeout属性和ontimeout事件处理程序
为支持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的实现
要请求位于另一个域中的资源,使用标准的XHR对象并在open()方法中传入绝对url即可
可以访问status和statusText属性,而且支持同步请求
- 跨域xhr对象的限制
- 不能使用setRequestHeader()设置自定义头部
- 不能发送和接收cookie
- 调用getAllResponseHeaders()方法总会返回空字符串
- 由于无论同源请求还是跨源请求都使用相同的接口,因此对于本地资源,最好使用相对url,在访问远程资源时再使用绝对url
Preflighted Requests
- 通过此验证机制支持开发人员使用自定义的头部、GET或POST之外的方法,以及不同类型的主体内容。在使用下列高级选项来发送请求时,就会向服务器发送一个Preflight请求。这种请求使用OPTIONS方法,发送下列头部
- Origin:与简单的请求相同
- Access-Control-Request-Method:请求自身使用的方法
- Access-Control-Request-Headers:(可选)自定义的头部信息,多个头部以逗号分隔
- 发送上述请求后,服务器可以决定是否允许这种类型的请求。服务器通过在响应中发送如下头部与浏览器进行沟通
- Access-Control-Allow-Origin:与简单的请求相同
- Access-Control-Allow-Methods:允许的方法,多个方法以逗号分隔
- Access-Control-Allow-Headers:允许的头部,多个头部以逗号分隔
- Access-Control-Max-Age:应该将这个Preflight请求缓存多长时间(秒)
- Preflight请求结束后,结果将按照响应中指定的时间缓存起来。而为此付出的代价只是第一次发送这种请求时会多一次HTTP请求
带凭据的请求
默认情况下,跨源请求不提供凭据(cookie、http认证及客户端ssl证明等)
将withCredentials属性设置为true,可以指定某个请求应该发送凭据
如果服务器接受带凭据的请求,会用下面的HTTP头部来响应
Access-Control-Allow-Credentials:true
如果发送的是带凭据的请求,但服务器的响应中没有包含这个头部,那么浏览器就不会把响应交给JavaScript。
服务器可以在Preflight响应中发送这个HTTP头部,表示允许源发送带凭据的请求
跨浏览器的CORS
检测xhr是否支持CORS的最简单方式,就是检查是否存在withCredentials属性。再结合检测XDomainRequest对象是否存在,就可以兼顾所有浏览器了
xhr和xdr共有的属性/方法:
- abort()
- onerror
- onload
- responseText
- send()
二、其他跨域技术
利用DOM中能够执行跨域请求的功能,不依赖xhr,也能发送某种请求
不需要修改服务器端代码
图像Ping
使用
<img>
标签。动态地创建图像,使用他们的onload和onerror事件处理程序来确定是否接收到了响应是与服务器进行简单、单向的跨域通信的一种方式。
请求的数据是通过查询字符串形式发送的,而响应可以是任意内容,但通常是像素图或204响应
最常用于跟踪用户点击页面或动态广告曝光次数
var img=new Image();img.onload-img.onerror=function(){ alert("Done!");};img.src="http://www.example.com/test?name=mary";
- 缺点:
- 只能发送GET请求
- 无法访问服务器的响应文本
JSONP
JSONP是JSON with padding的简写,是应用JSON的一种新方法,是包含在函数调用中的JSON。
callback({"name":"mary"});
由 回调函数和数据 组成
- 回调函数:当响应到来时应该在页面中调用的函数,函数的名字一般是在请求中指定的
- 数据:传入回调函数中的JSON数据
JSONP是通过动态
<script>
元素来使用的,使用时可以为src属性指定一个跨域url。与<img>
元素类似,都有能力不受限制地从其他域加载资源。在请求完成后,即在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);
- 可以直接访问响应文本,支持在浏览器与服务器之间双向通信
- 不足:
- 在使用不是你自己运维的web服务时,一定得保证它安全可靠
- 要确定JSONP请求是否失败并不容易,还没有任何浏览器支持
<script>
的onerror事件处理程序
Comet
Ajax是一种从页面向服务器请求数据的技术,而Comet则是一种服务器向页面推送数据的技术,能够让信息近乎实时地被推送到页面上,非常适合处理体育比赛的分数和股票报价
两种实现Comet的方式:
- 长轮询
- 流
长轮询是传统轮询(短轮询)的翻版。页面发起一个到服务器的请求,然后服务器一直保持连接打开,直到有数据可发送。发送完数据之后,浏览器关闭连接,随即又发起一个到服务器的新请求。这一过程在页面打开期间一直持续不断
无论长还是短,浏览器在接收数据之前,都要先发起对服务器的连接;区别是:短轮询是服务器立即发送响应,无论数据是否有效,而长轮询是等待发送响应
HTTP流,在页面的整个生命周期内只使用一个HTTP连接。就是浏览器向服务器发送一个请求,而服务器保持连接打开,然后周期性地向浏览器发送数据。
所有服务器端语言都支持打印到输出缓存然后刷新(将输出缓存中的内容一次性全部发送到客户端)的功能。这正式实现HTTP流的关键所在
在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");});
服务器发送事件
SSE是围绕**只读**Comet交互推出的API或者模式。用于创建到服务器的单向连接,服务器通过这个连接可以发送任意多的数据。
服务器响应的MIME类型必须是text/event-stream,而且是浏览器中的JavaScript API能解析格式输出。
SSE支持短轮询、长轮询、HTTP流,而且能在断开连接时自动确定何时重新连接
SSE API
- 创建一个新的EventSource对象,并传入一个入口点。传入的url必须与创建对象的页面同源(相同的url模式、域及其端口)
- 实例有一个readyState属性
- 0:正连接到服务器
- 1:打开了连接
- 2:关闭了连接
- 有三个事件
- open:在建立连接时触发
- message:在从服务器接收到新事件时触发
- error:在无法建立连接时触发
服务器发回的数据以字符串形式保存在event.data中
该对象会保持与服务器的活动连接。如果连接断开,还会重新连接。证明sse适合长轮询和HTTP流
- 立即断开连接而且不再重新连接,调用close()
事件流
服务器事件会通过一个持久的HTTP响应发送,这个相应的MIME类型为text/event-stream 。响应的格式是纯文本,最简单的情况是每个数据项都带有前缀data:
对于多个连续的以data:开头的数据行,将作为多端数据解析,每个值之间以一个换行符分隔。只有在包含data:的数据行后面有空行时,才会触发message事件
通过id:前缀可以给特定的事件指定一个关联的id,位于data:行之前之后都可以。设置了id后,EventSource对象会跟踪上一次触发的事件。如果连接断开,会向服务器发送一个包含名为Last-Event-ID的特殊HTTP头部的请求,以便服务器知道下一次该触发哪个事件
data:fooid:1data:bardata:foodata:bar
Web Sockets
在一个单独的持久连接上提供全双工、双向通信
在JavaScript中创建了Web Sockets之后,会有一个HTTP请求发送到浏览器以发起连接。在取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为Web Sokets协议。也就是说,使用标准的HTTP服务器无法实现Web Sokets,只有支持这种协议的专门服务器才能正常工作
- 由于Web Sockets使用了自定义的协议,所以url模式也略有不同。未加密的连接是ws://;加密的连接是wss://
Web Sockets API
实例化一个WebSocket对象并传入要连接的url(必须绝对url)。可以通过它打开到任何站点的连接。
表示当前状态的readyState属性,永远从0开始
- WebSocket.OPENING(0):正在建立连接
- WebSocket.OPEN(1):已经建立连接
- WebSocket.CLOSING(2):正在关闭连接
- WebSocket.CLOSE(3):已经关闭连接
- 没有readystatechange事件
- 关闭Web Socket连接,调用close(),之后readyState的值变为2,之后变为3
发送和接收数据
向服务器发送数据: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));
- 当服务器向客户端发来消息时,WebSoket对象就会触发message事件,这个事件把返回的数据保存在event.data属性中,数据是字符串
其他事件
在连接生命周期的不同阶段触发
- open:在成功建立连接时触发
- error:在发送错误时触发,连接不能持续
- close:在连接关闭时触发
不支持DOM2级事件侦听器,因此必须使用DOM0级语法分别定义每个事件处理程序
三、安全
对于未被授权系统有权访问某个资源的情况,称之为:CSRF
验证发送请求者是否有权访问相应的资源
- 要求以ssl连接来访问可以通过XHR请求的资源
- 要求每一次请求都要附带经过相应算法计算得到的验证码
- 高级程序设计——跨域技术
- 高级程序设计——高级定时器
- 高级程序设计——JSON
- 高级程序设计——Ajax
- JavaScript高级程序设计— 转换
- 《javascript高级程序设计》——模仿块级作用域
- 《javascript高级程序设计》——变量和作用域
- Javascript高级程序设计——11.变量、作用域、缓存
- 高级JS内容——JavaScript高级程序设计笔记
- PHP高级程序设计——抽象类
- 《JavaScript高级程序设计》——函数表达式
- 《JavaScript高级程序设计》——DOM
- Javascript高级程序设计读书笔记——继承
- javascript高级程序设计——笔记
- Javascript高级程序设计——6.函数
- javascript高级程序设计——笔记
- JS高级程序设计——Function类型
- 高级程序设计——打飞机小游戏
- 深度学习常用函数
- windows10 1709 wsl ubuntu ssh 报错
- Linux命令-进程|网络
- hdoj 4709 Herding
- 2017.12.9
- 高级程序设计——跨域技术
- 复习九:java Web部分、数据库部分
- awk过滤文本行
- 解决初次登录MySQL出现ERROR 1045 (28000):Access denied for user 'root'@'localhost'问题
- 回文树复习小记
- 同步容器&并发容器
- 分答项目_微擎数据库函数总结
- 前端开发之功能封装大全
- 求一串数组中和为定值的最长子串