根据一个网页可以从任何网页中加载图像而不用担心使用跨域的原理, 我们可以动态的创建图像, 使用他们的onload和onerror事件处理程序来确定是否收到响应。
动态的创建图像经常用于图像Ping。 图像Ping是与服务器进行简单的单向的跨域通信的一种方式。
请求的数据通过查询字符串形式发送的,而响应可以是任意内容, 但通常是 像素图 或者 204响应 。
通过图像Ping,浏览器得不到任何具体的数据, 但是通过侦听 load 和 error 事件, 它能知道是什么时候接受的。
var img = new Image(); img.onload = img.onerror = function() { alert("Done"); }; img.src = "http://ww.example.com/test?name=seacean";
图像Ping最常用于跟踪用户点击页面或动态广告曝光次数。
它有两个主要的缺点: 只能发送get请求,无法访问服务器的响应文本。 因此, 图像Ping只能用于浏览器与服务器间的单向通信。
JSONP是JSON with padding的简写,是应用json的一种新方法,在后来的Web服务中非常流行。
callback({ "name": "Oli" });
JSONP由两部分组成:回调函数和数据。
回调函数是当响应到来时应该在页面中调用的函数,回调函数的名字一般是在请求中指定的。数据就是传入回调函数的json数据。
下面是以个JSONP的例子:
http: //freegeoip.net/json/?callback=handleResponse //回调函数的名字就是handleResponse();
JSONP是通过动态的script元素来使用的,使用时可以为src属性指定一个跨域URL。这里的script元素有能力不受限制的同其他域加载资源。因为JSONP是有效地javascript代码,所以在请求完成后,即在JSONP响应加载到页面后会立即执行。
function handlerResponse(response) { alert("You're at IP address " + response.ip + ", where is in " + response.city + ", " + response.region_name); } var script = document.createElement("script"); script.src = "http://freegeoip.net/json/?callback=handlerResponse"; document.body.insertBefore(script, document.body.firstChild);
JSONP的优势:
在于简单易用,直接访问响应文本,支持浏览器与服务器之间的双向通信。
JSONP的不足之处:
不能确定加载的域是否安全,要确定请求失败并不容易。为了避免这些,开发人员的现行方案是用指定时间内是否接收到了响应来判断。
有两种实现Comet的方式:长轮询和流。
长轮询把传统轮询颠倒了一下,页面发送一个到服务器的请求,然后服务器一直保持连接打开,知道有数据可发送。发送完数据后,浏览器关闭连接,随即又发起一个到服务器的新请求。这个过程在页面打开期间一直不断持续。
第二种流行的Comet方式是HTTP流。流在页面的整个生命周期中只使用一个HTTP连接。具体来说就是浏览器向服务器发送一个请求,然后服务器保持连接打开,然后周期性的向浏览器发送数据。下面这段php脚本就是采用流实现的服务器中的常见方式:
$i = 0; while (true) { echo "Number is $i"; //输出数据然后刷新缓存 flush(); sleep(10); //停止几秒 $i++; }
这段代码是实现HTTP流的关键。
下面这段代码是XHR对象实现HTTP流的典型代码:
function createStreamingClient(url, progress, finished) { var xhr = new XMLHttpRequest(), received = 0; xhr.open("get", url, true); xhr.onreadystatechange = function() { var result; if (xhr.readyState == 3) { result = xhr.responseText.substring(received); received += result.length; progress(result); } else if (xhr.readyState == 4) { finished(xhr.responseText); } }; xhr.send(null); return xhr; } var client = createStreamingCilent("streaming.php", function(data) { alert("Received:" + data); }, function(data) { alert("Done!"); });
这个createStreamingCilent函数接收三个参数:要连接的URL,在接收到数据时调用的函数以及关闭连接时调用的函数。
SSE( Server - Sent Events, 服务器发送事件) 是围绕只读Comet交互推出的API或者模式。 SSE API用于创建到服务器的单向连接, 服务器通过这个连接可以发送任意数量的数据。 服务器响应的MIME类型必须是text / event - stream, 而且是浏览器中的Javascript API能解析的格式输出。 SSE支持短轮询, 长轮询和HTTP流, 而且能够在断开连接时自动确定何时重新连接。
SSE是为javascript api与其他传递消息的javascript api很相似。 要预定新的事件流, 要创建新的EventSource对象, 并传入一个入口点:
var source = new EventSource("myevents.php");
注意: 要传入的URL必须与创建对象的页面同源。 EventSource的实例有一个readyState属性, 值为0表示正连接到服务器, 值为1表示打开了连接, 值为2表示关闭连接。 另外还有三个事件:
open: 在建立连接时触发
message: 在从服务器接收到新事件时触发
error: 在无法建立连接时触发
服务器返回的数据以字符串的格式保存在event.data中。 如果想强制立即断开并且不再重新连接, 可以调用close() 方法。
多段数据发送时, 要以换行符进行分隔不同段的数据。 而且还可以在每段数据的前面或者后面附加ID, 以便多段数据的拼接。 在设置了ID之后, EventSource对象会跟踪上一次触发的事件。 如果连接断开, 会向服务器发送一个包含名为Last - Event - ID的特殊HTTP头部请求, 以便服务器知道下次触发那个事件。 在多次连接的事件流中, 这种机制保证了浏览器能够以正确的顺序接收到连接的数据段。
在js中web sockets使用了自定义的协议。 未加密的协议是ws: //;加密的协议是wss://.目前支持它的的浏览器有FireFox6+,safari5+,Chrome,IOS4+版safari。
创建web sockets的例子:
var sockets = new WebSockets("ws://www.example.com/server.php");
注意, 必须给WebSockets构造函数传入绝对的URL。 同源策略对它不适用。 能否与特定的域通信完全取决于服务器。
sockets.close(); //关闭 sockets.send("Hello word"); //可以发送字符串,json格式的字符串
sockets的事件有onmessage: 服务器向客户端发送消息, sockets会触发; onopen: 成功建立连接时触发; onerror: 在发生错误时触发, 连接时不能持续; onclose: 在连接关闭时触发。 在close事件中的event对象有三个额外的属性: wasClean, code, reason.第一个参数表示连接是否明确的关闭, 布尔值。 第二个是服务器返回的数值状态码, 而reason是一个字符串, 包含服务器返回的信息。
Web Sockets协议比同于HTTP, 现有的服务器不能用Web Sockets通信, HTTP可以满足要求。 如果只需要向服务器请求数据, 那么SSE比较容易, 要是双向的通信Web Sockets更好一些。 在不能使用Web Sockets的情况下, 组合XHR + SSE也能实现双向通信。
在AJAX安全方面, 下列措施是得力的:
要求以SSL连接来访问可以通过XHR请求的资源
要求每一次请求都要附带经过相应算法计算得到的验证码