Ajax
一、概述
1. Ajax概念
AJAX即Asynchronous Javascript And XML(异步JavaScript和XML),是改善用户体验的网页开发技术;
2. 传统交互方式与ajax交互方式
1. 传统交互方式:
客户端(浏览器)向服务器发送请求,服务器接收请求并处理完毕后会重新加载一个完整的网页(而且这个网页与之前的网页几乎差不多),并且将响应数据返回给客户端(浏览器),浏览器解析网页显示给用户;
缺点:
-
发送的请求是一个同步请求,销毁页面就不能继续操作;
-
修改的数据仅仅是页面中一小部分,然后响应的却是整个完整页面,浪费网络传输资源;
2. Ajax交互方式:
优点:
-
异步请求,发送请求的同事还可以继续操作页面。页面不销毁;
-
返回部分数据,减少不必要的数据承传输,介绍网络资源。页面不刷新,而是更新页面部分数据;
总结:Ajax出现的缘由:更好的提升用户的体验,以及提升服务器的效率,减少网络中不必要的数据的传送;
3. Ajax使用场景
-
自动提示:百度输入框自动提示功能;
-
用户名重复检查:用户注册时,检查用户名是否存在,及时给用户反馈;
-
邮箱提示:WEB版邮箱系统,当有新邮件到底服务器,浏览器不用刷新页面也知道是否有新邮件;
-
无刷新分页:显示数据列表,用户点击下一页数据,整个页面不会刷新,只把下一页的数据更新到页面中;
-
购物车:用户点击添加到购物车后,能继续进行其他操作,而购物车的数据存储服务器端;
-
用户登录:用户登录的数据通过AJAX传输到后台,如果登录失败直接在当前登录页面提示用户,而不用刷新整个页面;
-
视频网站,商城网站;
-
股票网站;
…
小技巧:浏览器网站的时候,留心观察很多页面未刷新,但是页面中的内容被更改了,这些都是AJAX使用场景; 99%的网站都会用到Ajax;
4.Ajax实质
-
写Ajax代码就是写js代码;
-
学习Ajax其实是学习使用浏览器的Ajax(XMLHttpRequest对象)对象发异步请求,将响应的数据局部更新到页面;
5.同步和异步
-
同步:你先做完我再做,后一步的操作必须要等待前一步操作的结果
-
异步:各做各的相互不干扰(效率高)
二、如何获取Ajax对象
-
AJAX对象本身是浏览器中的一个对象,但在低版本IE中表现为一个ActiveX。所以在使用JavaScript语言进行创建该对象时,Ajax没有标准化,需要区分不同的浏览器;
-
有时候我们会把XMLHttpRequest对象称为AJAX对象,或异步对象
创建方式1:判断方式
function getXhr(){
var xhr = null;
if(window.XMLHttpRequest){//针对其他浏览器
xhr = new XMLHttpRequest();
}else{//针对低版本的ie浏览器
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
return xhr;
}
创建方式2:try…catch…方式
var ajax;
try {
//如果是其它浏览器,这句代码可以成功,ajax对象就拿到了
ajax = new XMLHttpRequest();
} catch (e) {
//如果是IE,上面肯定会报错,被抓取,就执行下面这句代码(IE支持)
ajax = new ActiveXObject("Microsoft.XMLHTTP");
}
三、Ajax的Api
https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/open
1. onreadystatechange事件
onreadystatechange需要绑定一个事件处理函数,该函数用来处理readystatechange事件。当AJAX对象的 readyState的值发生了改变时,该事件由系统触发。比如,从0变成了1,就会产生readystatechange事件。在当前不同的处理状态下,可以进行状态的捕获,做些相应处理。每一次的状态变化都会触发onreadystatechange绑定的处理函数,只是大部分时候我们只需要知道从 3变为4,即当前readyState为4时这个状态,此时数据响应已返回,并接收成功,等待下一步的处理。格式如下:
只要 readyState
属性发生变化,就会调用相应的处理函数。这个回调函数会被用户线程所调用。XMLHttpRequest.onreadystatechange 会在 XMLHttpRequest
的readyState
属性发生改变时触发 readystatechange
事件的时候被调用。
警告:这个方法不该用于同步的requests对象,并且不能在内部(C++)代码中使用.
当一个 XMLHttpRequest
请求被 abort() 方法取消时,其对应的 readystatechange
事件不会被触发。
UPDATE: 在下面的浏览器版本中会触发 (Firefox 51.0.1, Opera 43.0.2442.991, Safari 10.0.3 (12602.4.8), Chrome 54.0.2840.71, Edge, IE11).
语法
XMLHttpRequest.onreadystatechange = callback;
取值
- 当
readyState
的值改变的时候,*callback*
函数会被调用。
示例
var xhr= new XMLHttpRequest(),
method = "GET",
url = "https://developer.mozilla.org/";
xhr.open(method, url, true);
xhr.onreadystatechange = function () {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
console.log(xhr.responseText)
}
}
xhr.send();
2. readyState请求状态
-
readyState代表请求的状态,使用不同的数字代表一个状态:
0:还没有调用send()方法
1:已经调用send(),正在发送请求
2:send()调用完成,已接收全部响应内容
3:正在解析响应内容
4:响应内容解析完毕,可以在客户端获取并使用了
-
对于状态的判断书写代码的格式如下:
xhr.onreadystatechange=function(){
if(xhr.readyState == 4){//已经接收到服务器响应的内容了
var txt = xhr.responseText;//展示数据到页面
}//这里最后不要写else,因为状态从0-1-2-3都会触发else
};
-
但是状态并不能保证回来的数据就是我们想要的数据,也可能是发回的错误提示。所以要想保证接受到的数据就是成功响应的数据,还需添加对另一个属性的判断(status)。这个属性代码响应的状态码,200代表成功,404代表没有找到资源,500代表服务器发生了运行异常;
-
服务器数据接收成功并且成功响应:
if(xhr.readyState == 4 && xhr.status == 200){
//接收服务端响应回来的数据(responseText只接收text文本)
var txt = xhr.responseText;
document.getElementById("uname").innerHTML = txt;
}else{
//发生了错误
document.getElementById("s").innerHTML ='验证用户名出错';
}
四、Ajax的编写步骤
1. 举个栗子:邮寄一个包裹
-
找到一个快递公司(获取ajax对象);
-
准备好包裹;
-
设置一个状态监听事件(发货单),查看或监听包裹发送的状态(未发送,已发送,在路上,已接收等状态);
-
发送包裹;
2. Ajax发送请求实现步骤
-
获取ajax对象(已经获取);
-
准备发送请求:xhr.open(“get”,"/xx/add")
-
设置回调函数(主要是获取服务器返回的正确数据):
xhr.onreadystatechange = function(){
......
}
- 发送请求:xhr.send()
3. 使用ajax对象发送get请求
-
获取ajax对象(已经获取) – 外部js文件中,当然也可以自己重新获取一次
-
准备发送请求:xhr.open(“get”,“uri?name=value”,true)
-
设置回调函数:
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
var text = xhr.responseText;
alert(txet);
}
}
- 发送请求:xhr.send(null)
代码实现:获取后台的数据更新到div中
测试:
-
测试获取readyState状态/有的浏览器0这个状态出不来;
-
测试不写后台代码,获取404页面的状态;
-
测试页面不刷新,局部更新;
-
测试正确状态;
4. 使用ajax对象发送post请求(多一步)
-
获取ajax对象(已经获取) – 外部js文件中,当然也可以自己重新获取一次
-
准备发送请求:xhr.open(“post”,“url”,true)
(1) url:参数可以写在url后,后台也可以获取到,但是一般post的请求参数不会直接写在地址栏中;
-
设置回调函数:
jsxhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
var text = xhr.responseText;
alert(txet);
}
}
- 设置请求头:
xhr.setRequestHeader(“content-type”,“application/x-www-form-urlencoded”);
注意:该操作必须在open与send之间调用,原因:
(1)open是创建一个请求,或者理解为请求的基本准备,如果没有请求,何来设置请求头信息;
(2)send是发送一个请求,请求会把当前请求的头信息进行发送,发送后设置头信息无效;
(3)如果js中没有参数传递到后台,可以省略这一步;
- 发送请求:xhr.send(“key=value”);
注意:记步骤,记方法,记get请求与post请求的差异;
五、Ajax编码问题
1. 为什么会有乱码?
-
乱码的根本原因在于编码和解码的方式不同而产生的;
-
IE浏览器提供的AJAX对象会使用GBK字符集对请求参数进行编码,而其它浏览器会使用UTF-8来编码。也就是不同的浏览器在发送请求时数据编码就已经不一致了;
-
对于服务器来讲,默认情况下会使用ISO-8859-1进行解码,这种解码格式是Tomcat的配置文件中声明的;
1.4.2. 解决GET请求时的乱码问题
-
前台:
- 使用encodeURI对请求地址进行编码。encodeURI会使用utf-8对请求地址中的中文参数进行编码:xhr.open(“get”, encodeURI(uri) , true);
-
后台:指定字符集进行解码(tomcat8及其以上不需要,默认就是UTF-8)
- Tomcat可以修改conf/server.xml文件中 ,使得tomcat按UTF-8方式解码;
3. POST请求时的乱码问题
-
因为所有浏览器在进行POST方式提交时都是使用UTF-8方式进行编码的,到了服务器端则默认使用ISO-8859-1方式来解码;
-
所以只需要修改服务器端的解码格式,保证是UTF-8的方式来解码就可以避免乱码:request.setCharacterEncoding(“UTF-8”);
六、Ajax Get提交IE缓存问题
-
IE浏览器提供的AJAX对象,在发送GET请求时,会先查看是否访问过该地址,如果该地址已经访问过,那么浏览器不再发送请求;
-
表现在页面上是,第一次点击某功能会得到数据,但是如果多次反复点击想获取最新数据时页面不会有任何变化,因浏览器发现地址相同而拒绝发出请求;
-
但这种页面表现只出现在IE浏览器中,Chrome浏览器和Firefox浏览器都能够实现数据的获取和页面的刷新;
-
缓存问题演示:从后台获取随机数更新到页面
-
测试结果:ie浏览器存在缓存问题,其他浏览器正常
-
如何解决:
(1) 发送post请求
(2) 欺骗浏览器,请它以为我们正在发送不同的请求:
- xhr.open(‘get’,‘random?r=’ + Math.random()); //通过随机数
地址已经访问过,那么浏览器不再发送请求;
-
表现在页面上是,第一次点击某功能会得到数据,但是如果多次反复点击想获取最新数据时页面不会有任何变化,因浏览器发现地址相同而拒绝发出请求;
-
但这种页面表现只出现在IE浏览器中,Chrome浏览器和Firefox浏览器都能够实现数据的获取和页面的刷新;
-
缓存问题演示:从后台获取随机数更新到页面
-
测试结果:ie浏览器存在缓存问题,其他浏览器正常
-
如何解决:
(1) 发送post请求
(2) 欺骗浏览器,请它以为我们正在发送不同的请求:
-
xhr.open(‘get’,‘random?r=’ + Math.random()); //通过随机数
-
xhr.open(‘get’,‘random?’ + (new Date()).getTime()); //通过时间戳