1. 何为Ajax请求?
ajax
请求技术是一种异步请求技术
,可以让浏览器在无需重新刷新页面的情况下,通过ajax
向后台发送请求并等后台数据响应后呈现在页面上。
也可以说,ajax
请求就是通过原生的XMLHttpRequest
对象发出的HTTP
请求,得到服务器返回的数据后,异步渲染在页面上。
2. Ajax请求步骤
ajax
请求的流程是:
- 浏览器给
xhr
对象说去服务器请求一些数据 - 然后浏览器自身并不会因为
xhr
对象去和服务器进行交互而处于阻塞的状况,而是会继续执行页面,此时xhr
会去向服务器发送请求 - 等到
xhr
对象从服务器获取了数据后,会通知给浏览器,从而将xhr
对象从服务器上获取到的数据渲染在页面上 - 整个过程都不需要刷新页面,因此称为
异步
ajax
的核心是xhr(XMLHttpRequest)
,使用xhr
发送ajax
请求的步骤为:
- 创建
XMLHttpRequest
实例 - 发送
HTTP
实例 - 监听请求
- 接收服务器返回的数据
- 异步渲染数据至页面
在jQuery
中,封装了ajax
作为网络请求的接口,那么我们就先来看看在jQuery
中,是如何调用ajax
来发送请求的吧:
$.ajax({
url: 'XXX',
type: 'get',
data: {
id: 1,
name: '张三'
},
dataType: 'json',
success: function (res) {
console.log(res);
}
});
通过上述调用ajax
的结构,基本上可以归纳出:
ajax
请求接收一个对象作为参数,该对象内包含进行网络请求时需要的url
地址,type
,请求参数,成功之后的回调函数等...
了解了ajax
请求的步骤后,我们就来自己上手封装一个ajax
吧~
2.1 第一步 生成默认参数
ajax
请求应包含请求的URL
、contentType
、success
、async
标识等基本信息。
用户在调用ajax
请求时不必填写每一项,可以只填写url
这种最基本的信息,以及根据需求决定是否需要传递其他参数。
- 如果用户没有传递某些参数,
ajax
就应该直接使用默认的值 - 如果用户传递了一些参数,就应该用传递进来的新值来替换默认值中对应的属性值
function ajax(opt) {
// 设置一些默认参数
let defaultParam = {
url: '#',
type: 'GET',
data: {},
contentType: 'application/json',
async: false,
success: function () {},
error: function () {}
}
// 用传递进来的新值来替换默认的属性值
for (let key in opt) {
defaultParam[key] = opt[key];
}
}
2.2 第二步 创建XMLHttpRequest实例
为了考虑不同浏览器之间的兼容性,我们需要根据当前浏览器是否包含XMLHttpRequest
对象来分别处理。
我们在前一个代码的基础上进一步完善:
function ajax(opt) {
// 第一步:设置一些默认参数
let defaultParam = {
url: '#',
type: 'GET',
data: {},
contentType: 'application/json',
async: false,
success: function () {},
error: function () {}
}
// 用传递进来的新值来替换默认的属性值
for (let key in opt) {
defaultParam[key] = opt[key];
}
// 第二步:声明xhr对象
let xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
}
2.3 打开请求(发送HTTP实例)
当声明了xhr对象后,我们就可以着手打开请求和发送请求的工作了。
打开请求这一步需要xhr
对象的open
方法和send
方法。 同时,对于不同的请求type
需要分别处理。
本文就简要处理GET
和POST
两种请求。
考虑到请求里可能需要携带参数,因此我们需要提前处理一下接收进来的data
:
function ajax(opt) {
// 第一步:设置一些默认参数
let defaultParam = {
url: '#',
type: 'GET',
data: {},
contentType: 'application/json',
async: false,
success: function () {},
error: function () {}
}
// 用传递进来的新值来替换默认的属性值
for (let key in opt) {
defaultParam[key] = opt[key];
}
// 处理参数格式备用
let paramStr = ''
for (let k in defaultParam.data) {
paramStr += k + '=' + defaultParam.data[k] + '&';
}
paramStr = paramStr.substr(0, paramStr.length - 1);
// 第二步:声明xhr对象
let xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
}
接下来,我们可以先写一下请求Type
为GET
的请求:
GET
相比于POST
请求来说,就简单多了,发送请求通过调用open
和send
两个方法 。 open()
函数里接收三个参数:
- 第一个参数是请求类型
- 第二个参数是请求
url
,如果有携带参数,就直接拼接在url
中即可 - 第三个参数是请求是否异步
send()
函数里不需要携带参数。
function ajax(opt) {
// 第一步:设置一些默认参数
let defaultParam = {
url: '#',
type: 'GET',
data: {},
contentType: 'application/json',
async: false,
success: function () {},
error: function () {}
}
// 用传递进来的新值来替换默认的属性值
for (let key in opt) {
defaultParam[key] = opt[key];
}
// 处理参数格式备用
let paramStr = ''
for (let k in defaultParam.data) {
paramStr += k + '=' + defaultParam.data[k] + '&';
}
paramStr = paramStr.substr(0, paramStr.length - 1);
// 第二步:声明xhr对象
let xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
// 第三步:发送请求
if (defaultParam.type === 'GET') {
xhr.open(defaultParam.type, defaultParam.url + "?" + paramStr, defaultParam.async);
xhr.send();
}
}
接下来,我们来完善POST
请求:
POST
请求相比于GET
请求的复杂之处在于:
![](/qrcode.jpg)
data
参数需要单独传递,不能拼接在url
里- 需要根据
contentType
设置请求头(因为不同的请求头,请求携带的参数格式不同)
如果contentType
为application/json
,那么传递的参数需要使用JSON.stringify
方法把data
转换为字符串传递给后台。
如果contentType
为application/x-www-form-urlencoded
,那么就直接传递我们之前处理好的paramStr
即可。
代码如下:
function ajax(opt) {
// 第一步:设置一些默认参数
let defaultParam = {
url: '#',
type: 'GET',
data: {},
contentType: 'application/json',
async: false,
success: function () {},
error: function () {}
}
// 用传递进来的新值来替换默认的属性值
for (let key in opt) {
defaultParam[key] = opt[key];
}
// 处理参数格式备用
let paramStr = ''
for (let k in defaultParam.data) {
paramStr += k + '=' + defaultParam.data[k] + '&';
}
paramStr = paramStr.substr(0, paramStr.length - 1);
// 第二步:声明xhr对象
let xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
// 第三步:发送请求,使用switch比if更优雅
if (defaultParam.type === 'GET') {
xhr.open(defaultParam.type, defaultParam.url + "?" + paramStr, defaultParam.async);
xhr.send();
} else {
xhr.open(defaultParam.type, defaultParam.url, defaultParam.async);
if (defaultParam.contentType === 'application/json') {
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(dafaultParam.data));//调用ajax时传递进来的参数
} else if (defaultParam.contentType === 'application/x-www-form-urlencoded') {
// 设置请求类型为formData
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(paramStr);//调用ajax时传递进来的参数,
}
}
}
2.4 监听请求
当我们发送完请求后,剩下的工作就是监听请求了:
- 调用
xhr.onreadystatechange
方法来监听请求 - 调用
xhr.readyState
来监听请求进度readyState
=== 0时,表明【未初始化】,还没有调用send()方法readyState
=== 1时,表明【载入】,已调用send()方法,正在发送请求readyState
=== 2时,表明【载入完成】,send()执行完成,已经接收到全部的响应内容readyState
=== 3时,表明【交互】,正在解析响应内容readyState
=== 4时,表明【完成】,响应内容解析完成,可以在客户端调用了
- 调用xhr.status来获取服务器响应的状态码
- 1XX:信息性状态码 ,表示接收的请求正在处理
- 2XX:成功状态码 , 表示请求正常处理
- 3XX:重定向状态码 ,表示需要附加操作来完成请求
- 4XX:客户端错误状态 ,表示服务器无法处理请求
- 5XX:服务器错误状态 ,表示服务器处理请求出错
如果readyState
=== 4
&& status
=== 200
,就代表请求发送成功,并且服务器端进行了正确的处理,此时客户端就可以根据服务器返回的数据进行下一步操作了。如果status
等于其他状态码,我们就需要处理异常,告诉客户端本次请求发送失败。
xhr.responseText
里存储着服务端返回给客户端的数据,该数据是JSON
格式的字符串,为了便于回调函数更方便的使用这些数据,我们需要使用JSON.parse
把它转换成JSON
格式,然后作为参数传递给success
这个回调函数,供其他组件使用。
完整代码如下:
function ajax(opt) {
// 第一步:设置一些默认参数
let defaultParam = {
url: '#',
type: 'GET',
data: {},
contentType: 'application/json',
async: false,
success: function () {},
error: function () {}
}
// 用传递进来的新值来替换默认的属性值
for (let key in opt) {
defaultParam[key] = opt[key];
}
// 处理参数格式备用
let paramStr = ''
for (let k in defaultParam.data) {
paramStr += k + '=' + defaultParam.data[k] + '&';
}
paramStr = paramStr.substr(0, paramStr.length - 1);
// 第二步:声明xhr对象
let xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
// 第三步:发送请求,使用switch比if更优雅
if (defaultParam.type === 'GET') {
xhr.open(defaultParam.type, defaultParam.url + "?" + paramStr, defaultParam.async);
xhr.send();
} else {
xhr.open(defaultParam.type, defaultParam.url, defaultParam.async);
if (defaultParam.contentType === 'application/json') {
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(dafaultParam.data));//调用ajax时传递进来的参数
} else if (defaultParam.contentType === 'application/x-www-form-urlencoded') {
// 设置请求类型为formData
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(paramStr);//调用ajax时传递进来的参数,
}
}
// 第四步:监听请求
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
let res = JSON.parse(xhr.responseText);
defaultParam.success(res);
}
}
}
}
至此,我们就完成了一个简易版原生Ajax的封装,又多了一项前端技能呢~