You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
functionhandleResponse(response){alert("you`re at IP address"+response.ip);}varscript=document.createElement('script');script.src='http://xx.net/json/?callback=handleResponse';docuemnt.body.insertBefore(script,document.body.firstChild);
<scripttype="text/javascript">
function addScriptTag(src){varscript=document.createElement('script');script.setAttribute("type","text/javascript");script.src=src;document.body.appendChild(script);}
window.onload = function(){//调用远程服务addScriptTag("http://localhost:20002/MyService.ashx?callback=person");}
//回调函数person
function person(data) {alert(data.name+" is a "+data.sex);}</script>
Web Sockets的目标是在一个单独的持久连接上提供全双工、双向通信。在JavaScript中创建了 Web Sockets之后,会有一个HTTP请求发送到浏览器以发送连接。在取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为Web Socket协议。也就是说,使用标准的HTTP服务器无法实现Web Sockets,只有支持这种协议的专门服务器才能正常工作。
由于 Web Sockets使用了自定义的协议,所以URL模式也略有不同。未加密的连接不再是http://而是ws://加密连接不再是https://而是wss://在使用Web Sockets URL时,必须带有这个模式,因为将来有可能支持其他模式。
其他跨域技术
在 CORS 出现之前,要实现 Ajax 跨域通信是比较困难的。开发人员们想出了一些方法,利用 DOM 中能够执行跨域请求的功能,在不依赖 XHR 对象的情况下也能发送某种请求。
图像Ping
我们知道一个网页可以从任何网页中加载图像。不用担心跨不跨域。可以动态地创建图像,使用他们的onload和onerror事件处理程序来确定是否接受到了响应。
动态创建图像经常用于图像Ping。图像Ping是与服务器进行简单、单向的跨域通信的一种方式。请求的数据是通过查询字符串的形式发送的、而响应可以是任意内容,但通常是像素图或者204响应。通过图像Ping,浏览器得不到任何具体的数据,但通过侦听load和error事件,它能知道响应是什么时候接收到的。
这这里我们创建了一个Image的实例,然后在onload 和onerror 事件处理程序指定为同一个函数。这样无论是什么响应,只要请求完成,就能得到通知。
请求从设置src属性你那一刻开始的。即图片的地址。
图像Ping最常用于跟踪用户点击页面或动态的曝光次数。但是他有两个缺点
图像Ping只能用于浏览器与服务器间的单向通信。
JSONP
JSONP是JSON with padding(填充式JSON或者参数式JSON) 的简写,是应用JSON的一种新方法。
JSONP看起来与JSON差不多,只不过被包含在函数调用中的JSON。例如:
callback({'name': 'mike'})
;JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时,应该在页面中调用的函数。回调函数的名字一般是在请求中的指定的。而数据就是传入回调函数中的JSON数据。
http://xx.net/json/?callback=handleResponse
上面这个例子,其中URL是在请求一个JSONP地理定位服务。通过查询字符串来指定JSONP服务的回调参数是很常见的,这里指定的回调函数的名字叫handleResponse()。
JSONP是通过动态的
<script>
元素来使用的,使用时可以为其src属性指定一个跨域的URL。这里的<script>
元素和<img>
元素类似,都有能力不受限制地从其他域加载资源。因为JSONP是有效的javascript代码,所以在请求完成后,即在JSONP响应加载到页面中以后,会立即执行。这个例子通过查询地理定位服务来显示你的IP地址。
JSONP非常流行,在于其很容易。与图像Ping相比,他的优点在于
* 能够直接访问文本
* 支持浏览器与服务器的双向通信
但是他有他的缺点:
* JSONP是从其他域加载代码执行,如果其他域不安全的话,很可能夹带一些恶意代码。
* 确定请求是否失败并不容易,如果动态脚本插入有效,就执行调用;如果无效,就静默失败。失败是没有任何提示的。例如,不能从服务器捕捉到 404 错误,也不能取消或重新开始请求。不过,等待一段时间还没有响应的话,就不用理它了。(未来的 jQuery 版本可能有终止 JSONP 请求的特性)。
看一个例子,在A域名下,请求B域名下资源。
Comet
Ajax是一种页面向服务器请求数据的技术,而Comet则是一种服务器向页面推送数据的技术。Comet能够让信息近乎实时地被推送到页面上,非常适合处理体育比赛的分数和股票报价。
Comet的实现方式:
长轮询:是传统轮询(也称短轮询)的一个翻版。短轮询---就是浏览器定时想服务器发送请求,看看有没有更新数据。而长轮询--就是页面发起一个到服务器的请求,然后服务器一直保持连接打开,直到有数据可发送。发送完数据之后,浏览器关闭连接,随后又发送一个到服务器的新请求。这一过程在页面打开期间一直持续不断。
无论是短轮询还是长轮询,浏览器都要在接受数据之前,先发起对服务器的连接。这两者最大的区别在于服务器如何发送数据。短轮询是服务器立即发送响应,无论数据是否有效,而长轮询是等待发送响应,轮询的优势在于所有浏览器都支持,因为使用XHR对象和setTimeout()就能实现。
HTTP流:它在页面的整个生命周期内只使用一个HTTP连接,具体来说,就是浏览器想服务器发送一个请求,而服务器保持连接打开,然后周期性的向浏览器发送数据。
例如下面这段PHP脚本就是采用流实现的服务器中常见的形式。
所有服务器语言都支持打印到输出缓存然后刷新(将输出缓存中的内容一次性全部发送到客户端)的功能。这正是实现HTTP流的关键所在。
在浏览器中,通过侦听readystatechange事件以及检测readyState的值是否为3,就可以利用XHR对象实现HTTP流。随着不断从服务器接受数据,readyState的值会周期性的变为3。当readyState的值为3时,responeseText属性中会保存接受到的数据,此时就需要比较接受到的数据,决定从什么位置开始取得最新的数据。
在这个createStreamingClient函数接受三个参数,要连接的URL、在接受到数据时调用的函数、以及关闭连接时调用的函数。有时候,当连接关闭时,很可能需要重新建立,所以关注连接什么时候关闭还是很有必要的。
只要readystatechange事件发生,而且readyState的值为3,就对responseText进行分割以取得最新数据,这里的received变量用于记录以及处理多少个字符,每次readyState的值为3时都以递增,然后,通过progress回调函数来处理传入的新数据,而的那个readyState的值为4时,则执行Finnish回调函数,传入响应返回的全部内容。
管理Comet的连接是很容易出错的,需要时间不断改进才能达到完美。
服务里发送事件
SSE(Server-Sent Events, 服务器发送事件)是围绕只读Comet交互推出的API或者模式,SSE API用于创建到服务器的单向连接,服务器通过这个连接可以发送任意数量的数据。服务器响应的MIME类型必须是
text/event-strem
而且是在浏览器中JavaScript API能解析可是输出。SSE支持短轮询、长轮询、HTTP流、而且能在断开连接是自动确定何时重新连接。用这个的话,实现Comet就容易很多了。SSE的JavaScript API与其他传递消息的JavaScript API很相似。要预定新的事件流,首先要创建一个显得EventSource对象,并传进一个入口点
var source = new EventSource('myevents.php');
注意,传入的URL必须与创建对象的页面同源。EvnetSource的实例有一个readyState属性,值为0表示正在连接服务器,值为1表示打开了连接,值为2表示关闭了连接。
还有3个事件。
就一般的用法而言,onmessage事件处理程序也没有什么特别的。
服务器发回的数据以字符串形式保存在event.data中。
默认的情况下,EventSource对象会保持与服务器的活动连接,如果连接断开,还会重新连接。这意味着SSE适合长轮询和HTTP流。如果想强制立即断开连接并且不再重新连接,可以调用close()方法。
source.close()
所谓的服务器事件会通过一个持久的HTTP响应发送,这个响应的MIME类型为
text/event-strem
.响应的格式是纯文本,最简单的情况是每个数据项都带有前缀data:,例如:对于以上响应而言,事件流中第一个message事件返回的event.data的值为foo,第二个message事件返回event.data值为bar...对于多个连续的以data:开头的数据行,将作为多段数据解析,每个值之前以一个换行符分隔。只有在包含data:的数据行后面有空行,才会触发message事件。因此在服务器上生产事件流是不能忘了多添加一行。
通过id:前缀可以给特定的事件指定一个关联的ID,这个ID行位于data:行前面或者后面皆可:
设置ID后,EventSource对象会跟踪上一次触发的事件。如果连接断开,会向服务器发送一个包含名为Last-Event-id特殊HTTP头部的请求,以便服务器知道下一次该触发那个事件。在多次连接事件流中,这种机制可以确保浏览器以正确的顺序收到连接的数据段。
Web Sockets
Web Sockets的目标是在一个单独的持久连接上提供全双工、双向通信。在JavaScript中创建了 Web Sockets之后,会有一个HTTP请求发送到浏览器以发送连接。在取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为Web Socket协议。也就是说,使用标准的HTTP服务器无法实现Web Sockets,只有支持这种协议的专门服务器才能正常工作。
由于 Web Sockets使用了自定义的协议,所以URL模式也略有不同。未加密的连接不再是
http://
而是ws://
加密连接不再是https://
而是wss://
在使用Web Sockets URL时,必须带有这个模式,因为将来有可能支持其他模式。使用自定义协议而非HTTP协议的好处:
使用自定义协议而非HTTP协议的缺点:
要创建Web Socket,先实例一个Web Socket对象并传入要连接的URL
var socket = new WebSocket('ws://www.example.com/server.php');
注意,必须给WebSocket构造函数传递绝对的URL,同源策略对Web Socket不适用。因此可以通过它打开任何站点的连接。至于是否会在某个域中的页面通信,则完全取决于服务器。
实例化WebSocket对象后,浏览器就会马上尝试创建连接,与XHR类似,WebSocket也有一个表示当前状态的readyState属性,不过,这个属性与XHR并不相同。而是如下所示:
WebSocket没有readystatechange事件,不过,它有其他事件,对应着不同的状态。redayState的值永远从0开始。
要关闭WebSocket连接,可以在任何时候调用close()方法。
socket.close()
调用close()之后,readyState的值立即变成2(正在关闭)。而在关闭连接后就会变成3
WebSocket打开之后,就可以通过连接发送和接受数据。要向服务器发送数据,使用send()方法并传入任意字符串。例如:
因为Web Socket只能通过连接发送纯文本数据,所以对于复杂的数据结构,在通过连接发送之前,必须进行序列化,例如:
接下来,服务器要读取其中的数据,就要解析接受到的JSON字符串。
当服务器想客户端发来消息时, WebSocket对象就会触发message事件。这个message事件与其他传递消息协议类似,也是把返回的数据保存在event.data属性中。
通过send()发送到服务器的数据一样,event.data中返回的数据也是字符串。如果你想得到其他格式的数据,必须手工解析这些数据。
WebSocket对象还有其他三个事件,在连接生命周期的不同阶段触发。
WebSocket对象不支持DOM2级事件侦听器,因此必须使用DOM0D级语法分别定义每个事件处理程序。
在这三个事件中,只有close事件的event对象有额外的信息,这个事件的事件对象有三个额外属性
wasClean
code
reason
。其中,wasClean
是一个布尔值,表示连接是否已经明确地关闭。code
是服务器返回的数值状态码。reason
是一个字符串,包含服务器发回的消息。可以把信息给用户,也可以记录到日志中以便将来分析SSE与Web Sockets
用SSE还是Web Sockets呢?可以从下面几个方面考虑:
你是否有自由度建立和维护Web Sockets的服务器?而SSE是通过常规的HTTP通信,现有的服务器就可以满足需求。
到底需不需要双向通信。如果只需要读取服务器数据(如比赛成绩),那么SSE比较容易实现,如果必须双向通信(例如聊天室)那么Web Sockets显然更好。
在不能选择Web Sockets的情况下,组合XHR和SSE也能实现双向通信。
安全
对于未被授权系统有权访问某个资源的情况,我们称之为CSRF(Cross-Site Request Forgery,跨站点请求伪造)。未被授权系统会伪装自己,让处理的请求服务器认为它是合法的。受到CSRF攻击的Ajax程序有大有小,攻击行为既有旨在揭示系统漏洞的恶作剧,也有恶意的数据窃取和数据销毁。
为了确保通过XHR访问的URL安全,通常的做法就是验证发送的请求者是否有权限访问相应的资源。有下列几种方式可供选择。
请注意,下列措施对防范CSRF攻击不起作用
XHR对象也提供一些安全机制,虽然表面上可以保证安全,但实际上却相当不可靠。实际上,open方法还能再接受两个参数: 要随请求一起发送的用户名和密码。带有这两个参数的请求可以通过SSL发送给服务器上的页面。例如:
xhr.open('get', 'example.php', true, 'username', 'password'); //不要这样做
因为只要打开控制器就能发现纯文本的用户名和密码。
The text was updated successfully, but these errors were encountered: