Ajax和Comet技术总结


Posted in Javascript onFebruary 19, 2017

Ajax是一种技术,一种能够向服务器请求额外的数据而无需卸载页面的技术,能够使网页具备更优的用户体验。Ajax技术的核心是XMLHttpRequest对象(XHR)。本文从XHR开始谈起,理解Ajax技术的特点,再对跨域以及Comet等技术进行简要理解和总结。

XMLHttpRequest基本用法

XHR对象有两个常用的方法open和send。open方法用户启动一个HTTP请求,不过它不会真的发送HTTP请求。open方法接收3个参数,分别表示请求的HTTP方法、请求的URL、是否异步。XHR对象的第二个方法send用于发送open所启动的请求。send方法接收1个参数,表示HTTP请求的主体数据。如果发送的是GET请求这种没有附带主体数据的HTTP请求,则传入null即可。如果是POST请求,则传入需要POST的数据。下面是一个简单示例,向/api/data发起一个GET请求,并且是采取异步的方式发送请求,即该请求不会阻塞页面中其他js代码的执行。

var xhr = new XMLHttpRequest()
xhr.open("get", "/api/data", true)
xhr.send(null)

请求得到的响应数据会自动填充到XHR对象的属性上,主要有下面4个属性:

* responseText: 响应主体文本
* responseXML: 如果响应内容类型是"text/xml"或"application/xml", 这个属性中将包含响应数据的XML DOM文档
* status: 响应的HTTP状态码,一般可以将HTTP状态吗200视为成功的标识
* statusText: HTTP状态的说明

XHR对象有1个readyState属性记录了该对象从创建到收到响应数据可能会经历的5种状态,readyState的可能取值如下:

0: 还没有调用open()方法初始化请求

1: 已经调用open()方法但是还没有调用send()方法

2: 已经调用send()方法但是还没有收到响应

3: 收到部分响应数据,还有部分数据没收到

4: 收到全部响应数据,即响应结束,数据完备

当readyState从一个值变到另一个值的时候会触发readystatechange事件,当这个事件触发的时候只需要在事件处理器里面检查一下readyState的值是否为4,当其值为4的时候就可以对响应的数据做后续处理了。给readystatechange事件指定处理器必须在调用open()方法之前完成才能确保跨浏览器兼容性。下面是简单示例。

var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function() {
 if (xhr.readyState === 4) {
  console.log(xhr.status, xhr.responseText)
 }
}
xhr.open("get", "/api/data", true)
xhr.send(null)

XHR对象提供setRequestHeader()方法可以设置请求的自定义HTTP头部信息,该方法接收两个参数,要设置的字段和该字段的值。在调用open()启动一个请求之后并且在send()发送请求之前调用setRequestHeader()才能设置成功。请求得到响应之后,可以通过getResponseHeader()方法获取响应的HTTP头部信息,该方法接收1个参数,即要获取的字段名。而通过getAllResponseHeaders()则可以获得所有头部信息组成的长字符串。下面是简单示例。

var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function() {
 if (xhr.readyState === 4) {
  console.log(xhr.status, xhr.responseText)
  console.log(xhr.getResponseHeader('SomeKey'))
  console.log(xhr.getAllResponseHeaders())
 }
}
xhr.open("get", "/api/data", true)
xhr.setRequestHeader("SomeKey", "SomeValue")
xhr.send(null)

FormData

XMLHttpRequest 2级定义了FormData类型为序列化表单、创建与表单格式相同的数据、用于XHR传输提供便利。FormData提供append()方法可以直接添加数据,该方法接收两个参数键和值。FormData的构造函数可以不传参数,也可以直接传入1个表单元素。传入表单元素之后会利用该表单元素的数据来向FormData对象预先填入键值对。下面是简单示例。

var form = document.getElementById('myForm')
var data = new FormData(form)
data.append('someKey', 'someValue')
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function() {
 if (xhr.readyState === 4) {
  console.log(xhr.responseText)
 }
}
xhr.open('post', '/api/upload', true)
xhr.send(data)

跨域资源共享

通过XHR实现Ajax通信会遇到一个限制,即跨域安全策略。跨域安全策略限制了“相同域名、相同端口、相同协议”,当XHR想要访问限制之外的资源就会引发安全错误。CORS(Cross-Origin Resource Sharing),跨域资源共享,其思想是通过使用自定义HTTP头部让浏览器与服务器进行沟通从而决定请求或者响应的成功与失败,需要浏览器和服务器同时支持才能实现正常的访问。目前大部分浏览器已经支持了CORS,所以写起代码跟普通的同域资源访问几乎一样,就只是把URL用绝对路径表示。因此,要实现跨域的关键还是在服务器,具体如何实现本文不深入讨论。下面是前端js的简单示例。

var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function() {
 if (xhr.readyState === 4) {
  console.log(xhr.responseText)
 }
}
xhr.open('get', 'http://www.otherserver.com/api/data', true)
xhr.send(null)

JSONP

JSONP(JSON with padding)是应用JSON实现跨域资源访问的一种方法。JSONP由两部分内容组成:回调函数和JSON数据。前面说过,XHR请求会遇到跨域安全策略的限制,但是HTML中的script标签则不会有这个限制,我们可以通过script标签引用不同域里面的js文件。JSONP便是钻了这个空子,它通过动态创建script元素,然后把src指向其他域的URL从而实现加载其他域的资源,然后通过回调函数来处理加载得到的数据。下面是一个简单示例。

function handler(res) {
 console.log(res)
}
var script = document.createElement('script')
script.src = 'http://www.otherserver.com/api/data/?callback=handler'
document.body.insertBefore(script, document.body.firstChild)

上述代码指定了动态创建的script元素的src为另一个域名下面的/api/data,然后指明回调函数为handler。将script插入到DOM里面之后会向对应的URL加载数据,完成之后会将得到的JSON数据解析成一个对象并调用handler进行处理。

JSONP是实现跨域访问的一种简单的方法,不过也存在一些安全问题,例如请求的其他域的URL响应给你一段恶意代码。JSONP还有一个问题,script标签引用的是js,json由于被js所支持所以也可以引用,因此在请求其他域的URL时需要确认它是否以json格式进行响应,而不是XML。

Comet

Ajax是一种从网页向服务器请求数据的技术,而Comet与之相反,它是从服务器向网页推送数据的技术,适用于实时性要求比较高的应用。实现Comet的方式有两种:长轮询和流。在说长轮询之前先说一下短轮询,它的思路很简单,就是客户端使用定时器,每隔一定的时间间隔就向服务器发送Ajax请求看看有没有数据更新,这个时间间隔一般很小。长轮询同样也是客户端不断向服务器发送请求,不同的是,客户端不需要按照时间间隔不断地发送请求,而是发起1个请求到服务器之后,客户端和服务器之间的HTTP连接保持打开,直到服务器有数据更新就通过这个连接向客户端响应数据,然后再关闭这个HTTP连接。关闭之后浏览器再发起一个新的连接继续重复前面的过程。相比短轮询,长轮询发起的HTTP连接次数更少了,不过如果HTTP连接长时间保持开放也是在占用服务器的资源。

第二种实现Comet的方式是基于HTTP流,客户端向服务器发起1个HTTP连接,全程保持这个连接打开,客户端周期性地通过这个连接向服务器获取数据查看更新。

SSE

SSE(Server-Send Events),服务器发送事件,是一种实现Comet交互的浏览器API,支持轮询也支持HTTP流。SSE API用于创建到服务器的单向连接,服务器通过这个连接可以发送任意数量的数据给客户端。服务器响应的MIME类型为text/event-stream。下面是SSE的JavaScript API的简单示例。

var source = new EventSource("/api/events")
source.onmessage = function(event) {
 console.log(event.data)
}

如上面代码所示,要向服务器预定事件流获取服务器发送的数据,首先创建EventSource对象,然后在message事件触发的时候进行处理。服务器发送的数据以字符串形式保存在event.data中。EventSource对象会保持与服务器的活动连接,如果中间断开会重新连接,如果要真正地断开连接可以通过调用close()方法来实现。EventSource的message事件会在从服务器收到新事件的时候触发,除了message事件之外它还有另外2个事件open和error,open事件在建立连接的时候触发,error事件在无法建立连接的时候触发。

Web Sockets

Web Sockets是一种与服务器进行全双工双向通信的通道。Web Sockets不适用HTTP协议,而前面说的Ajax和Comet都是使用HTTP协议。篇幅关系本文对Web Sockets不作讨论。

总结

Ajax实现在不加载页面的情况下向服务器请求数据,提升网页的用户体验。实现Ajax技术的XHR会遇到跨域安全策略的限制,通过CORS解决跨域问题需要浏览器和服务器两端的配合。JSONP是一种实现跨域访问的”小技巧“但也是存在一些问题。Comet对Ajax进行了拓展,让服务器能够实时向浏览器推送数据,但从实现来看不管是轮询还是HTTP流,都是浏览器先向服务器发起请求连接。Web Sockets的全双工双向通信也有其特色,以后有时间可以继续了解。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
apycom出品的jQuery精美菜单破解方法
Feb 18 Javascript
Jquery 例外被抛出且未被接住原因介绍
Sep 04 Javascript
javascript使用appendChild追加节点实例
Jan 12 Javascript
Jquery uploadify上传插件使用详解
Jan 13 Javascript
JQuery ztree 异步加载实例讲解
Feb 25 Javascript
JavaScript编码风格指南(中文版)
Aug 26 Javascript
实例讲解javascript实现异步图片上传方法
Dec 05 Javascript
AnglarJs中的上拉加载实现代码
Feb 08 Javascript
详解webpack编译速度提升之DllPlugin
Feb 05 Javascript
JavaScript Math对象和调试程序的方法分析
May 13 Javascript
JS图片懒加载的优点及实现原理
Jan 10 Javascript
JS实现页面炫酷的时钟特效示例
Aug 14 Javascript
thinkphp标签实现bootsrtap轮播carousel实例代码
Feb 19 #Javascript
Angularjs中的ui-bootstrap的使用教程
Feb 19 #Javascript
Java中int与integer的区别(基本数据类型与引用数据类型)
Feb 19 #Javascript
RequireJs的使用详解
Feb 19 #Javascript
Vue.js -- 过滤器使用总结
Feb 18 #Javascript
JS打开摄像头并截图上传示例
Feb 18 #Javascript
Android中Okhttp3实现上传多张图片同时传递参数
Feb 18 #Javascript
You might like
DOTA2游戏同人动画《龙之血》导演接受采访
2021/03/05 欧美动漫
域名查询代码公布
2006/10/09 PHP
php和数据库结合的一个简单的web实例 代码分析 (php初学者)
2011/07/28 PHP
PHP 第二节 数据类型之字符串类型
2012/04/28 PHP
php安装swoole扩展的方法
2015/03/19 PHP
PHP自定义递归函数实现数组转JSON功能【支持GBK编码】
2018/07/17 PHP
PHP使用PDO 连接与连接管理操作实例分析
2020/04/21 PHP
Prototype使用指南之hash.js
2007/01/10 Javascript
JS option location 页面跳转实现代码
2008/12/27 Javascript
用jquery存取照片的具体实现方法
2013/06/30 Javascript
浅谈JavaScript中指针和地址
2015/07/26 Javascript
跟我学习javascript的函数调用和构造函数调用
2015/11/16 Javascript
利用JS实现页面删除并重新排序功能
2016/12/09 Javascript
BootStrap整体框架之基础布局组件
2016/12/15 Javascript
使用BootStrap实现标签切换原理解析
2017/03/14 Javascript
HTML5+Canvas调用手机拍照功能实现图片上传(上)
2017/04/21 Javascript
浅谈Vue父子组件和非父子组件传值问题
2017/08/22 Javascript
超出JavaScript安全整数限制的数字计算BigInt详解
2018/06/24 Javascript
JavaScript实现动态添加、移除元素或属性的方法分析
2019/01/03 Javascript
es6数据变更同步到视图层的方法
2019/03/04 Javascript
Vue 修改网站图标的方法
2020/12/31 Vue.js
[55:45]LGD vs OG 2019国际邀请赛淘汰赛 胜者组 BO3 第三场 8.24
2019/09/10 DOTA
Python实现从脚本里运行scrapy的方法
2015/04/07 Python
Python中处理时间的几种方法小结
2015/04/09 Python
Python编程实现双击更新所有已安装python模块的方法
2017/06/05 Python
python3实现基于用户的协同过滤
2018/05/31 Python
Matplotlib绘制雷达图和三维图的示例代码
2020/01/07 Python
TensorFlow命名空间和TensorBoard图节点实例
2020/01/23 Python
Python 使用生成器代替线程的方法
2020/08/04 Python
Html5 Canvas实现图片标记、缩放、移动和保存历史状态功能 (附转换公式)
2020/03/18 HTML / CSS
全神贯注教学反思
2014/02/03 职场文书
人力资源职位说明书
2014/07/29 职场文书
2015年党员个人工作总结
2015/05/13 职场文书
赞美教师的句子
2019/09/02 职场文书
MySQL系列之三 基础篇
2021/07/02 MySQL
详细了解java监听器和过滤器
2021/07/09 Java/Android