目录
- 前言
- 一、课程介绍
- 二、json-server的介绍与服务搭建
- 三、axios的介绍与页面配置
- 四、axios的基本使用
- 五、axios其他方式发送请求
- 六、axios请求响应结果的结构
- 七、axios配置对象详细说明
- 八、axios的默认配置
- 九、axios创建实例对象发送请求
- 十、axios拦截器
- 十一、axios取消请求
- 十二、axios文件结构说明
- 十三、axios的创建过程
- 十四、axios对象创建过程模拟实现
- 十五、axios发送请求过程详解
- 十六、模拟实现axios发送请求
- 十七、axios拦截器工作原理
- 十八、模拟实现axios拦截器功能
- 十九、axios取消请求工作原理
- 二十、模拟实现axios取消请求功能
- 二十一、axios源码分析总结
- 写在后面
前言 在继续学习React-ajax之前,学完了Promise,再来学习axios
看的是b站尚硅谷李强老师的视频:axios从入门到源码分析
上一篇:Promise视频笔记
axios是目前前端最热门的ajax请求库,Vue和React官方都推荐使用axios进行ajax请求
一、课程介绍 内容包括三大部分:
- axios API 怎么安装怎么用
- 源码分析
- 源码仿写
全局安装json-server:
npm install -g json-server
创建json文件,内容是:
{
"posts": [
{ "id": 1, "title": "json-server", "author": "typicode" }
],
"comments": [
{ "id": 1, "body": "some comment", "postId": 1 }
],
"profile": { "name": "typicode" }
}
在该文件目录下运行:
json-server --watch db.json
这是对数据的获取
三、axios的介绍与页面配置 【前端|b站视频-尚硅谷Web前端axios从入门到源码分析-笔记】github—axios
axios是基于HTTP的客户端,可以在浏览器和node.js两个环境中运行:Promise based HTTP client for the browser and node.js
文章图片
安装:
npm install axios
四、axios的基本使用
axios基本使用
// 获取按钮
const btns=document.querySelectorAll('button');
// 第一个按钮 发送GET请求
btns[0].onclick=function(){
// 发送AJAX请求
axios({
// 请求类型
method:'GET',
// URL
url:'http://localhost:3000/posts/2',
}).then(response=>{
console.log(response);
});
}// 第二个按钮 发送POST请求 添加一篇新的文章
btns[1].onclick=function(){
// 发送AJAX请求
axios({
// 请求类型
method:'POST',
// URL
url:'http://localhost:3000/posts',
// 设置请求体
data:{
title: "今天天气很好",
author: "王五"
}
}).then(response=>{
console.log(response);
});
}// 第三个按钮 发送PUT请求 更新数据
btns[2].onclick=function(){
// 发送AJAX请求
axios({
// 请求类型
method:'PUT',
// URL
url:'http://localhost:3000/posts/3',
// 设置请求体
data:{
title: "今天天气很好",
author: "赵六"
}
}).then(response=>{
console.log(response);
});
}// 第四个按钮 发送DELETE请求 删除数据
btns[3].onclick=function(){
// 发送AJAX请求
axios({
// 请求类型
method:'delete',// 大小写都可以
// URL
url:'http://localhost:3000/posts/3',
}).then(response=>{
console.log(response);
});
}
五、axios其他方式发送请求
文章图片
// 获取按钮
const btns=document.querySelectorAll('button');
// 第一个按钮 发送GET请求
btns[0].onclick=function(){
// 与axios()使用方式一样
axios.request({
method:'GET',
url:'http://localhost:3000/comments'
}).then(response=>{
console.log(response);
});
}// 第二个按钮 发送POST请求 添加一个新的评论
btns[1].onclick=function(){
axios.post('http://localhost:3000/comments',
{
"body": "我是一条评论",
"postId": 2
}).then(response=>{
console.log(response);
});
}
六、axios请求响应结果的结构
文章图片
config:配置对象
data:响应体的结果
headers:响应头的信息
request:原生的AJAX请求对象
七、axios配置对象详细说明
文章图片
文章图片
.
.
.
文章图片
八、axios的默认配置
文章图片
// 获取按钮
const btns=document.querySelectorAll('button');
//默认配置
axios.defaults.method='GET';
// 设置默认的请求类型为GET
axios.defaults.baseURL='http://localhost:3000';
// 设置基础URL
axios.defaults.params={id:100};
axios.defaults.timeout=3000;
// 超时时间btns[0].onclick=function(){
axios({
url:'/posts',
}).then(response=>{
console.log(response);
});
}
九、axios创建实例对象发送请求
//创建实例对象
const duanzi = axios.create({
baseURL:'http://api.apiopen.top',
timeout:2000
});
// 给另一个协议、域名或端口不同的服务器发请求
const another = axios.create({
baseURL:'http://b.com',
timeout:2000
});
// 这里duanzi与axios对象的功能几近是一样的
// duanzi({
//url:'getJoke',
// }).then(response=>{
//console.log(response);
// });
duanzi.get('/getJoke').then(response=>{
console.log(response);
});
十、axios拦截器
文章图片
请求拦截器:对请求数据做处理
响应拦截器:对结果做处理
十一、axios取消请求
// 获取按钮
const btns=document.querySelectorAll('button');
// 2. 声明全局变量
let cancel=null;
// 发送请求
btn[0].onclick=function(){
axios({
method:'GET',
url:'http://localhost:3000/posts',
// 1. 添加配置对象的属性
cancelToken:new axios.CancelToken(function(c){
// 3. 将c的值赋给cancel
cancel=c;
})
}).then(response=>{
console.log(response);
})
}// 取消请求
btn[1].onclick=function(){
cancel();
}
上述方法,每次点击取消请求时,都没什么反应。因为服务器在本都,每次点击取消,请求都已经回来了。
解决方法:
①服务端做延时响应:
json-server --watch db.json -d 2000
②在发送请求时,看上个请求是否还在继续发送,若还在继续,就把它取消
// 发送请求
btn[0].onclick=function(){
// 检测上一次的请求是否已经完成
if(cancel!==null){
// 取消上一次的请求
cancel();
}
axios({
method:'GET',
url:'http://localhost:3000/posts',
// 1. 添加配置对象的属性
cancelToken:new axios.CancelToken(function(c){
// 3. 将c的值赋给cancel
cancel=c;
})
}).then(response=>{
console.log(response);
// 将cancel值复原
cancel=null;
})
}
十二、axios文件结构说明
文章图片
十三、axios的创建过程 分析源码:
axios既可以当函数使用,又可以调用方法
axios();
axios.get();
axios,post();
十四、axios对象创建过程模拟实现
//构造函数
function Axios(config){
//初始化
this.defaults = config;
//为了创建 default 默认属性
this.intercepters = {
request: {},
response: {}
}
}
//原型添加相关的方法
Axios.prototype.request = function(config){
console.log('发送 AJAX 请求 请求的类型为 '+ config.method);
}
Axios.prototype.get = function(config){
return this.request({method: 'GET'});
}
Axios.prototype.post = function(config){
return this.request({method: 'POST'});
}//声明函数
function createInstance(config){
//实例化一个对象
let context = new Axios(config);
// context.get()context.post()但是不能当做函数使用 context() X
//创建请求函数
let instance = Axios.prototype.request.bind(context);
// instance 是一个函数 并且可以 instance({})此时 instance 不能 instance.get X
//将 Axios.prototype 对象中的方法添加到instance函数对象中
Object.keys(Axios.prototype).forEach(key => {
instance[key] = Axios.prototype[key].bind(context);
// this.defaultthis.interceptors
});
//为 instance 函数对象添加属性 default 与 interceptors
Object.keys(context).forEach(key => {
instance[key] = context[key];
});
return instance;
}let axios = createInstance();
//发送请求
// axios({method:'POST'});
axios.get({});
axios.post({});
十五、axios发送请求过程详解 request–>dispatch–>xhr
十六、模拟实现axios发送请求
//1. 声明构造函数
function Axios(config){
this.config = config;
}
Axios.prototype.request = function(config){
//发送请求//创建一个 promise 对象
let promise = Promise.resolve(config);
//声明一个数组
let chains = [dispatchRequest, undefined];
// undefined 占位
//调用 then 方法指定回调
let result = promise.then(chains[0], chains[1]);
//返回 promise 的结果
return result;
}//2. dispatchRequest 函数
function dispatchRequest(config){
//调用适配器发送请求
return xhrAdapter(config).then(response => {
//响应的结果进行转换处理
//....
return response;
}, error => {
throw error;
});
}//3. adapter 适配器
function xhrAdapter(config){
console.log('xhrAdapter 函数执行');
return new Promise((resolve, reject) => {
//发送 AJAX 请求
let xhr = new XMLHttpRequest();
//初始化
xhr.open(config.method, config.url);
//发送
xhr.send();
//绑定事件
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
//判断成功的条件
if(xhr.status >= 200 && xhr.status < 300){
//成功的状态
resolve({
//配置对象
config: config,
//响应体
data: xhr.response,
//响应头
headers: xhr.getAllResponseHeaders(), //字符串parseHeaders
// xhr 请求对象
request: xhr,
//响应状态码
status: xhr.status,
//响应状态字符串
statusText: xhr.statusText
});
}else{
//失败的状态
reject(new Error('请求失败 失败的状态码为' + xhr.status));
}
}
}
});
}//4. 创建 axios 函数
let axios = Axios.prototype.request.bind(null);
axios({
method:'GET',
url:'http://localhost:3000/posts'
}).then(response => {
console.log(response);
});
十七、axios拦截器工作原理
// 设置请求拦截器
// config:配置对象,在请求拦截器中我们可以对config进行调整、修改
axios.interceptors.request.use(function (config) {
console.log('请求拦截器 成功 - 1号')
// 修改config中的参数
config.params={a:100}
config.timeout=2000return config;
//throw '参数出了问题'
}, function (error) {
console.log('请求拦截器 失败 - 1号')
return Promise.reject(error);
});
axios.interceptors.request.use(function (config) {
console.log('请求拦截器 成功 - 2号')
// return config;
throw '参数出了问题'
}, function (error) {
console.log('请求拦截器 失败 - 2号')
return Promise.reject(error);
});
// 设置响应拦截器
// response 我们可以对响应结果做一些处理
axios.interceptors.response.use(function (response) {
console.log('响应拦截器 成功 - 1号')
// 我们可以对响应结果做一些处理
return response.data;
// return response;
}, function (error) {
console.log('响应拦截器 失败 - 1号')
});
axios.interceptors.response.use(function (response) {
console.log('响应拦截器 成功 - 2号')
return response;
}, function (error) {
console.log('响应拦截器 失败 - 2号')
});
// 发送请求
axios({
method:'GET',
url:'http://localhost:3000/posts'
}).then(response=>{
console.log('自定义回调处理成功的结果');
// console.log(response);
}).catch(response=>{
console.log('自定义失败回调');
// console.log(response);
});
运行结果:
文章图片
node_modules/axios/lib/core/Axios.js文件中:
文章图片
十八、模拟实现axios拦截器功能
//构造函数
function Axios(config){
this.config = config;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager(),
}
}
//发送请求难点与重点
Axios.prototype.request = function(config){
//创建一个 promise 对象
let promise = Promise.resolve(config);
//创建一个数组
const chains = [dispatchRequest, undefined];
//处理拦截器
//请求拦截器 将请求拦截器的回调 压入到 chains 的前面request.handles = []
// console.log( this.interceptors.request.handlers);
this.interceptors.request.handlers.forEach(item => {
chains.unshift(item.fulfilled, item.rejected);
});
//响应拦截器
this.interceptors.response.handlers.forEach(item => {
chains.push(item.fulfilled, item.rejected);
});
// console.log(chains);
//遍历
while(chains.length > 0){
promise = promise.then(chains.shift(), chains.shift());
}return promise;
}//发送请求
function dispatchRequest(config){
//返回一个promise 队形
return new Promise((resolve, reject) => {
resolve({
status: 200,
statusText: 'OK'
});
});
}//创建实例
let context = new Axios({});
//创建axios函数
let axios = Axios.prototype.request.bind(context);
//将 context 属性 config interceptors 添加至 axios 函数对象身上
Object.keys(context).forEach(key => {
axios[key] = context[key];
});
// console.dir(axios);
//拦截器管理器构造函数
function InterceptorManager(){
this.handlers = [];
}
InterceptorManager.prototype.use = function(fulfilled, rejected){
this.handlers.push({
fulfilled,
rejected
})
}//以下为功能测试代码
// 设置请求拦截器config 配置对象
axios.interceptors.request.use(function one(config) {
console.log('请求拦截器 成功 - 1号');
return config;
}, function one(error) {
console.log('请求拦截器 失败 - 1号');
return Promise.reject(error);
});
axios.interceptors.request.use(function two(config) {
console.log('请求拦截器 成功 - 2号');
return config;
}, function two(error) {
console.log('请求拦截器 失败 - 2号');
return Promise.reject(error);
});
// 设置响应拦截器
axios.interceptors.response.use(function (response) {
console.log('响应拦截器 成功 1号');
return response;
}, function (error) {
console.log('响应拦截器 失败 1号')
return Promise.reject(error);
});
axios.interceptors.response.use(function (response) {
console.log('响应拦截器 成功 2号')
return response;
}, function (error) {
console.log('响应拦截器 失败 2号')
return Promise.reject(error);
});
// console.dir(axios);
//发送请求
axios({
method: 'GET',
url: 'http://localhost:3000/posts'
}).then(response => {
console.log(response);
});
十九、axios取消请求工作原理
文章图片
二十、模拟实现axios取消请求功能
//构造函数
function Axios(config){
this.config = config;
}
//原型 request 方法
Axios.prototype.request = function(config){
return dispatchRequest(config);
}
//dispatchRequest 函数
function dispatchRequest(config){
return xhrAdapter(config);
}
//xhrAdapter
function xhrAdapter(config){
//发送 AJAX 请求
return new Promise((resolve, reject) => {
//实例化对象
const xhr = new XMLHttpRequest();
//初始化
xhr.open(config.method, config.url);
//发送
xhr.send();
//处理结果
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
//判断结果
if(xhr.status >= 200 && xhr.status < 300){
//设置为成功的状态
resolve({
status: xhr.status,
statusText: xhr.statusText
});
}else{
reject(new Error('请求失败'));
}
}
}//关于取消请求的处理
if(config.cancelToken){
//对 cancelToken 对象身上的 promise 对象指定成功的回调
config.cancelToken.promise.then(value => {
xhr.abort();
//将整体结果设置为失败
reject(new Error('请求已经被取消'))
});
}
})
}//创建 axios 函数
const context = new Axios({});
const axios = Axios.prototype.request.bind(context);
// console.dir(axios);
//CancelToken 构造函数
function CancelToken(executor){
//声明一个变量
var resolvePromise;
//为实例对象添加属性
this.promise = new Promise((resolve) => {
//将 resolve 赋值给 resolvePromise
resolvePromise = resolve
});
//调用 executor 函数
executor(function(){
//执行 resolvePromise 函数
resolvePromise();
});
}//获取按钮 以上为模拟实现的代码
const btns = document.querySelectorAll('button');
//2.声明全局变量
let cancel = null;
//发送请求
btns[0].onclick = function(){
//检测上一次的请求是否已经完成
if(cancel !== null){
//取消上一次的请求
cancel();
}//创建 cancelToken 的值
let cancelToken = new CancelToken(function(c){
cancel = c;
});
axios({
method: 'GET',
url: 'http://localhost:3000/posts',
//1. 添加配置对象的属性
cancelToken: cancelToken
}).then(response => {
console.log(response);
//将 cancel 的值初始化
cancel = null;
})
}//绑定第二个事件取消请求
btns[1].onclick = function(){
cancel();
}
二十一、axios源码分析总结 axios与Axios的关系:
- 从语法上来说,axios不是Axios的实例
- 从功能上来说,axios是Axios的实例
- axios是Axios.prototype.request函数bind()返回的函数
- axios作为对象有Axios原型对象上的所有方法,有Axios对象上所有属性
- 相同点:都既可以当函数用,又可以当对象去用,而且都有默认配置和拦截器的属性
- 不同点:默认配置很可能不一样,instance没有axios后续添加的一些方法
axios的请求/响应拦截器是什么:
axios 的请求/响应数据转换器是什么:
response 的整体结构:
error 的整体结构:
如何取消未完成的请求:
写在后面 看完了这21个视频,完结撒花,强哥还是很强的哈。关于源码分析,也就是12~21,没认真看,如果以后有需要再认真学习一下吧。学完了Promise与axios,继续去学习React了
推荐阅读
- 前端|b站视频-尚硅谷Web前端Promise从入门到精通-笔记
- 【华为联机对战】下载运行华为官方Unity示例代码,提示鉴权失败并返回错误码100114
- 前端|Element-UI 表单校验
- javaScript|JS中ES6的模块化
- vue.js|ES6模块化开发
- ES6新特性|ES6新特性-模块化(import/export)
- 如何设置网页 favicon 图标
- 面试题|【Web前端面试】葵花宝典(2022版本)——HTTP\浏览器 篇
- 手写axios