前端网络请求Ajax原理与封装(碎片化学习)
前端网络请求封装
我们平时和服务端打交道都需要使用到网络请求,但是平时开发中我们一般都用别人封装好的比如 ajax、axios,或者使用更简单的原生fetch方法(以后再讲这个方法的封装)。我们学习的时候更要知其然知其所以然,所以今天我们就来看看如何封装一个最基础的网络请求函数。
了解Ajax
XMLHttpRequest
(XHR)对象用于与服务器交互。通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。XMLHttpRequest
在Ajax编程中被大量使用
readyState的4个状态
-
0 - (未初始化)还没有调用send()方法 -
1 - (载入)已调用send()方法,正在发送请求 -
2 - (载入完成)send()方法执行完成,已经接收到全部响应内容 -
3 - (交互)正在解析响应内容 -
「4 - (完成)响应内容解析完成,可以在客户端调用了 (主要)」
请求状态码(Status)
「1XX:」 信息,服务器收到请求,需要请求者继续执行操作(不常用)
「2XX:」 成功,操作被成功接收并处理 。「常见:200-OK(正常返回)、201-Created(成功创建)、204 - No Content(网页未更新时,服务器正常处理但没返回内容)」
「3XX:」 重定向,需要进一步的操作以完成请求 。「常见:301 - Moved Permanently (永久重定向, 请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI )、302 - Found(临时重定向,资源临时被移动,客户端应继续使用原有URI )、304 - Not Modified( 未修改。请求的资源未修改,不返回任何资源。客户端通常会缓存访问过的资源)」
「4XX:」 客户端错误状态 ,表示服务器无法处理请求。「常见:400 - Bad Request (客户端请求语法错误,服务器无法理解 )、401 - Unauthorized(未授权,一般是需要先登录授权)、403 - Forbidden ( 服务器理解请求,但是拒绝执行 ,一般用于某些页面权限的设置)、404 - Not Found(资源访问不到)」
「5XX:」 服务器错误,处理请求的过程中发生了错误 。常见:500( 服务器内部错误,无法完成请求 )、 503(超载或者在维护,暂时无法处理请求)
封装请求函数
回调函数版本
function ajax(options) {
// ES6解构并赋予默认值
const { url, method = 'GET', sync = true, responseType = 'json' } = options;
const xhr = new XMLHttpRequest();
xhr.open(method, url, sync);
// 设置响应的类型,默认为json
xhr.responseType = responseType;
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
// 成功的回调
options.success(xhr.response);
}
};
xhr.onerror = (err) => {
// 错误的回调
options.fail(err);
};
// 此处只处理 get 和 post 请求,还有 put、delete、options的请求就不处理了
if (method === 'GET') {
xhr.send();
}
// POST 请求需要发送请求体
if (method === 'POST') {
xhr.send(options.data);
}
}
ajax({
url: '此处填写需要发送请求的地址',
success: (res) => {
// 拿到服务端返回的数据
console.log(res);
},
fail: (err) => {
console.log('错误处理', err);
},
});
Promise 版本
Promise 版本我们只是在函数内返回了一个Promise,并将结果和错误抛出去,这种方式更加推荐,因为回调函数版本会形成“回调地狱”的问题。“回调地狱”指的是函数层级不断的嵌套。
function ajax(options) {
return new Promise((resolve, reject) => {
// ES6解构并赋予默认值
const { url, method = 'GET', sync = true, responseType = 'json' } = options;
const xhr = new XMLHttpRequest();
xhr.open(method, url, sync);
xhr.responseType = responseType;
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
resolve(xhr.response);
}
};
xhr.onerror = (err) => {
reject(err);
};
// 此处只处理 get 和 post 请求,还有 put、delete、options的请求就不处理了
if (method === 'GET') {
xhr.send();
}
if (method === 'POST') {
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(options.data);
}
});
}
ajax({ url: '此处填写需要发送请求的地址' })
.then((res) => {
// 拿到服务端返回结果
console.log(res);
})
.catch((err) => {
// 错误处理
console.log(err);
});