JavaScript高级程序设计-第三版(Ajax与Comet)

二十一、Ajax与Comet

  • Ajax
    • Asynchronous JavaScript + XML

21.1 XMLHttpRequest对象

21.1.1 XHR的用法

  • XMLHttpRequest实例方法
    • open()
      • 接收参数
        • 请求类型
        • 请求URL
          • 当前页面的相对URL或者绝对路径
        • 是否异步发送请求
      • 不会真正发送请求,而是启动一个请求以备发送
    • send()
      • 接收参数
        • 请求主体发送的数据
    • abort()
      • 在接收响应前取消异步请求
      • XHR对象属性无法访问
  • 响应
    • 自动填充XMLHttpRequest实例属性
      • responseText
      • responseXML
        • 响应内容类型为"text/xml"或"application/xml"时自动填充该属性
        • 保存响应数据的XML DOM文档
      • status 状态码
      • statusText
    • 同步响应
      • 立即填充XMLHttpRequest实例属性
    • 异步响应
      • XMLHttpRequest实例属性readyState表示请求/响应过程的当前活动阶段
        • 取值
          • 0 尚未调用open()
          • 1 尚未调用send()
          • 2 尚未接收响应
          • 3 接收到部分响应
          • 4 接收到全部响应
        • readystatechange 事件
          • 监控readystate值改变,判断响应接收
          • 指定事件处理程序
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
	if(xhr.readyState==4){
		if((xhr.status>=200 && xhr.status<300) || xhr.status == 304 ){
			alert(xhr.responseText);
		}else{
			alert("Request was unsuccessful:"+ xhr.status);
		}
	}
};
xhr.open("get","example.txt",true);
xhr.send(null);

21.2.2 HTTP头部信息

  • 发送请求
    • 默认携带以下头部信息
      • Accept
      • Accept-Charset
      • Accept-Encoding
      • Accept-Language
      • Connection
      • Cookie
      • Host
      • Referer
      • User-Agent
    • 可以设置自定义头部信息
      • xhr.setRequestHeader( key, value )
      • 在调用open()方法之后,send()方法之前设置
  • 接收响应
    • 获取服务端设置的自定义头部信息
      • xhr.getResponseHeader( key )
      • xhr.getAllResponseHeaders()
        • 格式化的多行文本内容

21.1.3 GET请求

  • 查询字符串需要追加到URL末尾
    • 键和值需要使用encodeURIComponent()进行编码

21.1.4 POST请求

  • 数据作为请求的主体提交
    • 通过send()进行发送

21.2 XMLHttpRequest 2级

21.2.1 FormData

  • 方便创建与表单格式相同的数据
  • 构建FormData对象
    • 手动添加
      • append( key, value )
    • 通过表单DOM创建
      • 将表单DOM作为构造函数的参数
  • 作为send()的参数传递数据
var data = new FormData();
data.append("name","Nicholas");

var data = new FormData(document.forms[0]);

xhr.send(data);

21.2.2 超时设定

  • XHR对象的实例属性 timeout
    • 请求在等待响应多少毫秒之后就终止
    • 此时无法访问XHR对象的status属性
  • 超时会触发timeout事件
xhr.timeout = 1000;
xhr.ontimeout = function(){
	alert("Request did not return in a second.");
};
xhr.send(null);

21.2.3 overrideMimeType()方法

  • 重写XHR响应的MIME类型
    • 服务器返回"text/plain",但数据实际包含XML,此时responseXML属性中为null,而重写MIME类型,可以保证把响应当作XML而非纯文本处理
xhr.overrideMimeType("text/xml");
xhr.send(null);

21.3 进度事件

  • 进度事件包括以下6个
    • loadstart 在接收响应数据的第一个字节时触发
    • progress 响应期间持续触发
    • error
    • abort
    • load 接收到完整的响应数据时触发
    • loadend
  • 每个请求从触发loadstart开始,一个或多个progress事件,然后触发error、abort或load事件中的一个,最后触发loadend事件

21.3.1 load事件

  • 不需要监控readystatechange事件来判断响应结束
var xhr = new XMLHttpRequest();
xhr.onload = function(){
	if((xhr.status>=200 && xhr.status<300) || xhr.status == 304 ){
		alert(xhr.responseText);
	}else{
		alert("Request was unsuccessful:"+ xhr.status);
	}
};
xhr.open("get","example.txt",true);
xhr.send(null);

21.3.2 progress事件

  • event对象中包含3个属性
    • lengthComputable 进度信息是否可用
    • position 已经接收的字节数
    • totalSize 根据Content-length响应头部确定的预期字节数
var xhr = new XMLHttpRequest();
xhr.onprogress = function(event){
	var divStatus = document.getElementById("status");
	if(event.lengthComputable){
		divStatus.innerHTML = "Received "+ event.position + " of " + event.totalSize + " bytes";
	}
};
xhr.open("get","example.txt",true);
xhr.send(null);

21.4 跨源资源共享

  • 同源
    • 协议、域名、端口号都相同
  • 跨源资源共享CORS(Cross-Origin Resource Sharing)
    • 发送请求时附加自定义HTTP头部
    • 服务器根据头部信息判断是否给予响应
    • 服务器回发相同的响应头部信息
    • 浏览器匹配请求头部和响应头部信息

21.4.1 IE对CORS的实现

  • 引入类似XHR的XDR ( XDomainRequest )
  • XDR
    • 实现了安全可靠的跨域通信,可直接使用
    • cookie不会随请求发送
    • 只能设置请求头部信息中的Content-Type字段
    • 不能访问响应头部信息
    • 只支持GET和POST请求

21.4.2 其他浏览器对CORS的实现

  • XHR原生支持CORS
    • 只需在open()中传入绝对URL路径
    • 不能设置自定义头部
    • 不能发送和接收cookie
    • 调用getAllResponseHeaders()会返回空字符串

21.4.3 Preflighted Requests

  • 在正式请求前先发送一个临时请求(使用OPTIONS方法),该请求包含以下头部信息
    • Origin
    • Access-Control-Request-Method
    • Access-Control-Request-Headers
  • 服务器在接到请求后,返回以下响应头部
    • Access-Control-Allow-Origin
    • Access-Control-Allow-Method 多个用逗号隔开
    • Access-Control-Allow-Headers 多个用逗号隔开
    • Access-Control-Allow-Age Preflight请求缓存时间
  • 在指定的缓存时间内,可以进行跨域通信,且支持
    • 自定义头部
    • GET或POST之外的方法
    • 不同类型的主体内容

21.4.4 带凭据的请求

  • 默认情况下,跨源请求不提供凭据(cookie、HTTP认证以及客户端SSL证明等)
  • 将withCredentials属性设置为true可以指定请求应该发送凭据
  • 若服务器不响应Access-Control-Allow-Credentials:true,则响应内容不会放置到responseText,status为0,且触发error事件

21.4.5 跨浏览器的CORS

21.5 其他跨域技术

21.5.1 图像Ping

  • <img>标签不用担心跨域问题,但只能单向向服务器发送请求,浏览器无法访问服务器响应的内容
  • 服务器一般响应像素图或204(请求成功,但不返回数据)
  • 可以通过load或者error事件监控响应完成
  • img.src = “http”//www.example.com/test?name=Nicholas"

21.5.2 JSONP

  • JSONP(JSON with padding)填充式JSON
    • 包含在函数调用中的JSON
  • <script>标签链接外部脚本时,不用担心跨域问题
  • 可以实现双向通信
    • 服务器接收浏览器传递的回调函数名,响应对函数进行调用的字符串,callbackFun( { “name” : “Nicholas” } )
    • 浏览器<script>标签默认将字符串解析为javascript脚本,实现回调
  • 该方式需要保证访问的域是安全可靠的
function handleResponse(response){
	alert("You're at IP address "+ response.ip + ",which is in " +
	response.city + ", " + response.region_name);
}
var script = document.createElement("script");
script.src = "http://freegeoip.net/Test?callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);
function Test(callback){
	...
	return callback+"({\"ip\":\"127.0.0.1\",\"city\":\"New York\",\"region_name\":\"regionA\"})";
}

21.5.3 Comet

  • Comet
    • 服务器向页面推送数据
    • 适合处理体育比赛的分数和股票报价
  • 实现Comet的两种方式
    • 长轮询
      • 短轮询的翻版
        • 短轮询是浏览器不断向服务器请求数据,服务器收到请求后立马向浏览器返回数据
      • 长轮询是浏览器不断向服务器请求数据,服务器收到请求后不会立马返回数据,但始终保持连接,在有数据或者数据变化时才返回
    • HTTP流
      • 浏览器向服务器发送请求,服务器保持连接打开,并周期性的向浏览器发送数据
        • 调用Stream的flush()刷新缓存写数据,而不调用close()
      • 服务器在向浏览器写数据时,浏览器的readyState会周期性的变为3,只有当流关闭后,readyState才会变为4
      • 服务器向浏览器写数据是追加的方式,浏览器的responseText保存的是接收到的所有数据
        • 可以通过定义一个变量的方式记录每次收到数据后在responseText中的索引位置
var received = 0;
var result = xhr.responseText.substring(received);
received + = result.length;

21.5.4 服务器发送事件

  • SSE(Server-Sent Events)
    • 为方便实现只读Comet的交互而推出的API
    • 服务器响应的MIME类型必须是 text/event-stream
    • 单向通信,服务器向浏览器传递数据
21.5.4.1 SSE API
  • 创建EventSource对象,并传入一个请求的URL(同源)
    • var source = new EventSource(“myevents.php”)
  • EventSource
    • 实例属性
      • readyState
        • 0 正在连接服务器
        • 1 打开连接
        • 2 关闭连接
    • 默认情况下,EventSource对象会保持与服务器的活动连接,断开后会自动重连
    • 实例方法
      • close() 永久断开连接
  • 事件
    • open 建立连接时触发
    • message 接收到新事件时触发
    • error 无法建立连接时触发
21.5.4.2 事件流
  • 服务器返回的数据必须有空行才会触发message事件
  • id: 前缀可以给指定的事件指定一个关联的ID(在数据行前面或者后面),在重连时可以确定上次已发送的数据
    • 重连时,浏览器自动发送一个包含名为Last-Event-ID的特殊HTTP头部的请求

21.5.5 Web Sockets

  • Web Sockets
    • 在一个单独的持久连接上提供全双工、双向通信
  • 创建Web Socket之后,会有一个HTTP请求发送到浏览器以发起连接。在取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为Web Socket协议
  • URL模式
    • 未加密 ws:// 对应http://
    • 加密 wss:// 对应https://
21.5.5.1 Web Sockets API
  • 构造WebSocket对象,传入要连接的绝对URL(不适用同源策略)
  • WebSocket
    • 实例属性
      • readyState
        • WebSocket.OPENING——0 正在建立连接
        • WebSocket.OPEN——1 已经建立连接
        • WebSocket.CLOSING——2 正在关闭连接
        • WebSocket.CLOSE——3 已经关闭连接
      • 没有readyState事件
    • 实例方法
      • close()
21.5.5.2 发送和接收数据
  • send() 只能传入字符串
  • 接收到服务器的响应后,会触发message事件
21.5.5.3 其他事件
  • open
  • error
  • close
    • event对象具有额外属性
      • wasClean 连接是否已经明确关闭
      • code 服务器返回的状态码
      • reason 服务器发送的消息

21.5.6 SSE与Web Sockets

  • Web Sockets需要建立专门的Web Sockets服务器
  • Web Sockets支持双向通信,SSE需要和XHR结合实现双向通信

21.6 安全

  • 访问数据需要相应授权
  • CSRF(Cross-Site Request Forgery)跨站点请求伪造
    • 不可靠的验证方式
      • 要求发送POST
      • 验证来源URL
      • 基于cookie信息的验证
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值