第二十一章 Ajax与Comet

ajax

Ajax 的定义

ajax 是对 Asynchronous JavaScript + XML 的简写,实现了向服务器请求额外数据时无需卸载或刷新页面。

XMLHttpRequest 对象

创建 XHR 对象

ie 浏览器中可能会存在多个 XHR 对象 获取方式如下

// 获取 XHR版本
function createXHR() {
  if (typeof arguments.callee.activeXString !== "string") {
    var versions = [
        "MSXML2.XMLHttp.6.O",
        "MSXML2.XMLHttp.3.0",
        "MSXML2.XMLHttp",
      ],
      i,
      len;
    for (i = 0, len = versions.length; i < len; i++) {
      try {
        new ActiveXObject(versions[i]);
        arguments.callee.activeXString = versions[i];
        break;
      } catch (ex) {
        // 跳过
      }
    }
    return new ActiveXObject(arguments.callee.activeXString);
  }
}

ie7 以上和其他浏览器都支持原生的 XHR 对象 可以直接创建

new XMLHttpRequest();

XHR 的用法

open()

调用 open 方法并不会直接发送请求,只是启动一个请求
open 接收三个参数

  • 请求类型
  • URL
  • 是否异步发送
setRequestHeader()

设置自定义的头部信息,这个方法接受两个参数

  • 头部字段的名称
  • 头部字段的值

overrideMimeType()

XHR 的 overrideMimeType 方法用来重写响应的 MIME 类型。

send()

send 接收一个参数,作为请求主体的数据,如果没有需要穿 null

getAllResponseHeaders() & getResponseHeader()

获取响应头信息

abort()

取消异步请求

返回体

在收到响应后,响应的数据会自动填充 XHR 对象的属性

  • responseText: 响应主体
  • responseXML 响应数据中的 XML DOM 文档
  • status 响应的 HTTP 状态
  • statusText 状态说明
  • readyState 请求/响应过程中的当前活动状态
    • 0:未初始化 未调用 open
    • 1:启动 未调用 send
    • 2:发送 未收到响应
    • 3:接收 接收到部分数据
    • 4:完成 接受到全部数据并且可以在客户端使用

当 readyState 值变化时会触发 onreadystatechange

HTTP 头部信息

在发送 XHR 请求时,会发送一些头部信息

  • Accept 浏览器能够处理的内容类型
  • Accept-Charset 浏览器能够显示的字符集。
  • Accept-Encoding 浏览器能够处理的压缩编码。
  • Accept-Language 浏览器当前设置的语言
  • Connection 浏览器与服务器之间连接的类型
  • Cookie 当前页面设置的任何 Cookie。
  • Host 发出请求的页面所在的域。
  • Referer 发出请求的页面的 URI
  • User-Agent 浏览器的用户代理字符串
  • Content-Type 有请求体情况下 请求体格式

GET 请求

查询字符串需添加到 URL 末尾,用(?)开头,参数之间用(&)符号隔开,参数值格式有问题需用 encodeURIComponent() 方法

POST 请求

请求体需要放入 send 方法中

XMLHttpRequest 2 级

FormData

使用 FormData 可以很方便的传输请求内容,并且不必设置请求头。

超时设定

XHR 的 timeout 属性可以设置超时毫秒时间,如果超出还未接到响应就会触发 ontimeout 事件。

overrideMimeType

XHR 的 overrideMimeType 方法用来重写响应的 MIME 类型。

进度事件

  • loadstart 在收到响应数据第一个字节时触发
  • progress 在接收响应期间持续不断地触发
  • error 在请求发生错误时触发
  • abort 在因为调用 abort()而终止连接时触发
  • load 在接收到完整的响应数据时触发
  • loadend 在通信完成或者触发 error、abort 或 load 事件后触发。

每个请求都从触发 loadstart 事件开始,接下來是一或多个 progress 事件,然后触发 error、
abort 或 load 事件中的一个,最后以触发 loadend 事件结束。

跨源资源共享

由于跨域安全策略。默认情况下,XHR 对象只能访问与包含它的页面位于同一个域中的资源。
CORS 背后的基本思想,就是使用自定义的 HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
在发送该请求时,需要给它附加一个额外的 origin 头部,其中包含请求页面的源信息(协议、域名和端
口),以便服务器根据这个头部位息来决定是否给予响应
如果服务器认为这个请求可以接受,就在 Access-Control-Allow-Origin 头部中回发相同的源
信息(如果是公共资源,可以回发*)。

注意,请求和响应都不包含 cookie 信息。

其他跨域技术

图像 Ping

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

JSONP

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

function handleResponse(response) {
  alert(response);
}
var script = document.createElement("script");
script.src = "http://freegeoip.net/json/?ca1lback=handLeResponse";
document.body.insertBefore(script, document.body.firstChild);

Comet

Comet 是一种服务器向页面推送数据的技术。
有两种实现 Comet 的方式:长轮询和流。
长轮询是传统轮询(也称为短轮询)的一个翻版,即浏览器定时向服务器发送请求,看有没有更新的数据。长轮询把短轮询颠倒了一下。页面发起一个到服务器的请求,然后服务器一直保持连接打开,直到有数据可发送。发送完数据之后,浏览器关闭连接,随即又发起一个到服务器的新请求。
第二种流行的 Comet 实现是 HTTP 流。流不同于上述两种轮询,因为它在页面的整个生命周期内只使用一个 HTTP 连接。具体来说,就是浏览器向服务器发送一个清求,而服务器保持连接打开,然后周期性地向浏览器发送数据。通过侦听 readystatechange 事件及检测 readyState 的值是否为 3,就可以利用 XHR 对象实现 HTTP 流。随着不断从服务器接收数据,readyState 的值会周期性地变为 3。当 readyState 值变为 3 时,responseText 属性中就会保存接收到的所有数据。此时,就需要比较此前接收到的数据,决定从什么位置开始取得最新的数据。

服务器发送事件

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

SSE API

首先要创建一个新的 Eventsource 对象
传入的 URL 必须与创建对象的页面同源

var source = new EventSource("myevents.php");

Eventsource 的实例有一个 readyState 属性,值为 0 表示正连接到服务器,值为 1 表示打开了连接,值为 2 表示关闭了连接。
还有以下三个事件

  • open;在建立连接吋触发。
  • message:在从服务器接收到新事件时触发。
  • error:在无法建立连接时触发。

如果想强制立即断开连接并且不再重新连接,可以调用 close ()方法。

Web Sockets

Web Sockets 的目标是在一个单独的持久连接上提供全双工、双向通信。在 JavaScript 中创建了 Web Socket 之后,会有一个 HTTP 请求发送到浏览器以发起连接。在取得服务器响应后,建立的连接会使用 HTTP 升级从 HTTP 协议交换为 Web Socket 协议。也就是说,使用标准的 HTTP 服务器无法实现 Web Sockets,只有支持这种协议的专门服务器才能正常工作。
由于 Web Sockets 使用了自定义的协议,所以 URL 模式也略有不同。未加密的连接不再是 http://,而是 ws://;加密的连接也不是 https://,而是 wss://。

Web Sockets API

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

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

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

实例化了 WebSocket 对象后,浏览器就会马上尝试创建连接。与 XHR 类似,WebSocket 也有一
个表示当前状态的 readystate 属性。不过,这个属性的值与 XHR 并不相同,而是如下所示。

Websocket.OPENING (0):正在建立连接 0
WebSocket.OPEN (1):已经建立连接。
WebSocket.CLOSING (2):正在关闭连接。
WebSocket.CLOSE (3):已经关闭连接。

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

发送和接收数据

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

var message = {
  time: new Date(),
  text: "Hello world!",
  clientld: "asdfp8734rew",
};
socket.send(JSON.stringify(message));

当服务器向客户端发来消息时,WebSocket 对象就会触发 message 事件。

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

data 中返回的数据也是字符串。

其他事件

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

  • open:在成功建立连接时触发。
  • error:在发生错误时触发,连接不能持续。
  • close:在连接关闭时触发。

SSE 与 Web Sockets

面对某个具体的用例,在考虑是使用 SSE 还是使用 Web Sockets 时, 可以考虑如下几个因索。首先,你是否有自由度建立和维护 Web Sockets 服务器?因为 Web Socket 协议不同于 HTTP,所以现有服务器不能用于 Web Socket 通信。SSE 倒是通过常规 HTTP 通信,因此现有服务器就可以满足需求。
第二个要考虑的问题是到底需不需要双向通信。如果用例只需读取服务器数据(如比赛成绩),那么 SSE 比较容易实现。如果用例必须双向通信(如聊天室),那么 Web Sockets 显然更好。别忘了,在不能选择 Web Sockets 的情况下,组合 XHR 和 SSE 也是能实现双向通信的。

安全

为确保通过 XHR 访问的 URL 安全,通行的做法就是验证发送请求者是否有权限访问相应的资源。
有下列几种方式可供选择。

  • 要求以 SSL 连接来访问可以通过 XHR 请求的资源。
  • 要求毎一次请求都要附带经过相应算法计算得到的验证码。

请注意,下列措施对防范 CSRF 攻击不起作用。

  • 要求发送 POST 而不是 GET 请求----容易改变。
  • 检査来源 URL 以确定是否可信----来源记录很容易伪造。
  • 基于 cookie 信息进行验证----同样很容易伪造。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值