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 相关文章推荐
javascript与webservice的通信实现代码
Dec 25 Javascript
编程语言JavaScript简介
Oct 16 Javascript
javascript中apply、call和bind的使用区别
Apr 05 Javascript
JavaScript基础语法之js表达式
Jun 07 Javascript
JavaScript解八皇后问题的方法总结
Jun 12 Javascript
angularjs使用directive实现分页组件的示例
Feb 07 Javascript
vue2.0 常用的 UI 库实例讲解
Dec 12 Javascript
细说webpack源码之compile流程-入口函数run
Dec 26 Javascript
深入理解vue-class-component源码阅读
Feb 18 Javascript
深入解析vue 源码目录及构建过程分析
Apr 24 Javascript
详解微信小程序网络请求接口封装实例
May 02 Javascript
JavaScript的Proxy可以做哪些有意思的事儿
Jun 15 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
php结合飞信 免费天气预报短信
2009/05/07 PHP
thinkphp视图模型查询提示ERR: 1146:Table 'db.pr_order_view' doesn't exist的解决方法
2014/10/30 PHP
PHP设计模式之单例模式定义与用法分析
2019/03/26 PHP
XHTML-Strict 内允许出现的标签
2006/12/11 Javascript
Javascript !!的作用
2008/12/04 Javascript
jQuery与ExtJS之选择实例分析
2010/08/19 Javascript
Jquery中"$(document).ready(function(){ })"函数的使用详解
2013/12/30 Javascript
jQuery+CSS3实现树叶飘落特效
2015/02/01 Javascript
Nodejs下用submit提交表单提示cannot post错误的解决方法
2016/11/21 NodeJs
js+html制作简单日历的方法
2017/06/27 Javascript
JavaScript实现购物车基本功能
2017/07/21 Javascript
Angular通过angular-cli来搭建web前端项目的方法
2017/07/27 Javascript
详解vue-meta如何让你更优雅的管理头部标签
2018/01/18 Javascript
微信小程序wx.getImageInfo()如何获取图片信息
2018/01/26 Javascript
基于打包工具Webpack进行项目开发实例
2018/05/29 Javascript
利用Decorator如何控制Koa路由详解
2018/06/26 Javascript
Layui实现带查询条件的分页
2019/07/27 Javascript
Python中变量交换的例子
2014/08/25 Python
实例说明Python中比较运算符的使用
2015/05/13 Python
Python global全局变量函数详解
2018/09/18 Python
Django重置migrations文件的方法步骤
2019/05/01 Python
Python学习笔记之读取文件、OS模块、异常处理、with as语法示例
2019/06/04 Python
python3实现在二叉树中找出和为某一值的所有路径(推荐)
2019/12/26 Python
使用PyTorch将文件夹下的图片分为训练集和验证集实例
2020/01/08 Python
matplotlib 三维图表绘制方法简介
2020/09/20 Python
利用CSS3制作简单的3d半透明立方体图片展示
2017/03/25 HTML / CSS
Europcar西班牙:全球汽车租赁领域的领导者
2018/09/17 全球购物
意大利顶级奢侈品电商:LUISAVIAROMA(支持中文)
2020/05/26 全球购物
出生医学证明样本
2014/01/17 职场文书
诚信考试倡议书
2014/04/15 职场文书
导游词之藏龙百瀑景区
2019/12/30 职场文书
python3实现常见的排序算法(示例代码)
2021/07/04 Python
Qt自定义Plot实现曲线绘制的详细过程
2021/11/02 Python
python中pycryto实现数据加密
2022/04/29 Python
pytest实现多进程与多线程运行超好用的插件
2022/07/15 Python
如何用H5实现好玩的2048小游戏
2022/07/23 HTML / CSS