2022年10月11日,在《AXAJ与JavaScript中的异步编程元素》文章中我总结了对于前端开发者中需要了解和掌握的8种异步编程元素,其中XMLHTTPRequest很关键,它是原生JavaScript提供的用于发送 HTTP 请求的对象,用于在前端与服务器进行数据交互。
  XMLHTTPRequest提供了基本的网络请求功能,但使用起来相对繁琐,需要编写大量的代码来处理不同阶段的请求、响应和错误,即使这些对这些处理做了很好的封装也一样。
  曾经很流行的JQuery中的AXAJ就是对XMLHTTPRequest进行了很好的封装,让开发者能够很方便灵活地使用。

  随着JQuery逐渐淡出,axios在很多前端框架中占据了主流(比如vue+elementUI框架),它也是对XMLHttpRequest(在Node.js 环境中封装的是http模块)进行了很好的封装,提供了一个更为优雅和强大的接口来发送 HTTP 请求。axios基于Promise,允许开发人员以链式调用的方式处理 HTTP 响应的成功和失败情况,从而简化了异步代码的书写和流程控制。

  一、axios的常用方法
  1. 发送 GET 请求:axios.get(url[, config])。
  2. 发送 POST 请求:axios.post(url[, data[, config]])。
  3. 发送 PUT 请求:axios.put(url[, data[, config]])。
  4. 发送 DELETE 请求:axios.delete(url[, config])。
  5. 发送 HEAD 请求:axios.head(url[, config])。
  6. 发送 OPTIONS 请求:axios.options(url[, config])。
  7. 发送 PATCH 请求:axios.patch(url[, data[, config]])。
  axios 提供的各种方法分别对应HTTP规范中定义的不同请求方法,它们各自有不同的用途,通常与 RESTful API 设计标准保持一致,也是为了让axios操作更加语义化。
  对应的后端操作(NodeJS):

constexpress=require('express');
constmyapp=express();

myapp.get('/api',(req,res)=>{
	//处理get请求
});

myapp.post('/api',(req,res)=>{
	//处理post请求
});

myapp.put('/api',(req,res)=>{
	//处理put请求
});

myapp.delete('/api',(req,res)=>{
	//处理delete请求
});

myapp.patch('/api',(req,res)=>{
	//处理patch请求
});

myapp.head('/api',(req,res)=>{
	//处理head请求
});

myapp.options('/api',(req,res)=>{
	//处理OPTIONS请求
});

  在平常的开发中,我们经常使用的是get和post方法,通常是在这两个操作中完成对数据的增、删、改、查。

  二、axios的编码范式

  axios是一个基于Promise的HTTP客户端,在JavaScript代码中使用axios库时,有几种常见的编码范式。
  以axios的get方法为例,下面是常见的用法。
  ⑴基本使用

        axios.get('http://127.0.0.1:1234/user')
            .then(function (res) {
                console.log(res);
            })
            .catch(function (err) {
                console.error(err);
        });

        axios({
            url:'http://127.0.0.1:1234/user',
            method:'get'
        }).then(function (res) {
                console.log(res);
            })
            .catch(function (err) {
                console.error(err);
        });

  ⑵带有参数

        axios.get('http://127.0.0.1:1234/user', {
            params: {
            ID: 2
            }
        })
        .then(function (res) {
            console.log(res);
        })
        .catch(function (err) {
            console.error(err);
        });

        axios({
            url:'http://127.0.0.1:1234/user', 
            method:'get',
            params: { ID: 2 }
        })
        .then(function (res) {
            console.log(res);
        })
        .catch(function (err) {
            console.error(err);
        });

  ⑶通过async/await使用

        async function getUserInfo() {
            try {
                const res = await axios.get('http://127.0.0.1:1234/user?ID=2');
                console.log(res);
            } catch (err) {
                console.error(err);
            }
        }

        getUserInfo();

  ⑷创建axios实例

        const myAxios = axios.create({
            baseURL: 'http://127.0.0.1:1234',
            timeout: 2000,
        });

        myAxios.get('/user?ID=2')
            .then(function (res) {
                console.log(res);
        }).catch(function (err) {
            console.error(err);
        });        

  三、axios的链式编程
  很多前端开发者喜欢链式编程写法。
  链式编程中如果任何一个请求发生错误,最后的catch方法都将捕获并统一处理错误,这是方便的地方,但是过多的链式编程给调试带来不必要的麻烦。

        Mock.mock('http://127.0.0.1:1234/user?name=vue',{
            'user':{'Id':1 }
        })

        Mock.mock('http://127.0.0.1:1234/user?userId=1',{
            'info':{'title':'vue + elementUI + Admin' }
        })        

        axios.get('http://127.0.0.1:1234/user?name=vue')
        .then(function (res) {
            return res.data.user.Id;
        })
        .then(function (userId) {
            return axios.get('http://127.0.0.1:1234/user?userId='+userId);
        })
        .then(function (res) {
            console.log(res.data.info.title);
        })
        .catch(function (err) {
            console.err(err);
        });

  程序最后输出:vue + elementUI + Admin。

  四、axios处理并发请求

        Mock.mock('http://127.0.0.1:1234/getUserName',{            
                        'name':'vue'             
        })

        Mock.mock('http://127.0.0.1:1234/getUserInfo',{
                        'Framework':'vue + elementUI + Admin' 
        })

        function getUserName() {
            return axios.get('http://127.0.0.1:1234/getUserName');
        }

        function getUserInfo() {
            return axios.get('http://127.0.0.1:1234/getUserInfo');
        }

        Promise.all([getUserName(), getUserInfo()])
        .then(function (res) {
            const arr1 = res[0];
            const arr2 = res[1];
            // 处理结果
            console.log(arr1.data.name);
            console.log(arr2.data.Framework);
        });

        axios.all([getUserName(), getUserInfo()])
        .then(function (res) {
            const arr1 = res[0];
            const arr2 = res[1];
            // 处理结果
            console.log(arr1.data.name);
            console.log(arr2.data.Framework);
        });

  如果不使用axios.all()或者Promise.all()来执行,让两个axios单独执行,那么可能由于axios完成时间的不同,导致不同的axios获取结果存在先后顺序;但是放在axios.all()或者Promise.all()中来执行,那么就是等待这两个都完成再一起输出结果。

  现在流行的写法是使用箭头函数:

        axios.all([getUserName(), getUserInfo()])
            .then(res=>{
                console.log(res);
                for(let i=0;i<res.length;i++){
                    console.log(res[i].data);
                }
        });        

  或者:

        axios.all([getUserName(), getUserInfo()])
            .then(axios.spread(
                (res1,res2) => {
                console.log(res1.data.name);
                console.log(res2.data.Framework);
        }));    

  五、创建axios实例
  一般写法:

        const myAxios=axios.create();

        myAxios.defaults.baseURL="http://127.0.0.1:1234";

        myAxios.request({
            method:'get',
            url:'/user',
            timeout: 2000,
            headers: {'X-Custom-Header': 'foobar'}            
        }).then(
            res=>{ console.log(res.data.name); }
        )

  或者:

        const myAxios=axios.create({
            baseURL:"http://127.0.0.1:1234",
            timeout: 2000,
            headers: {'X-Custom-Header': 'foobar'}            
        });

        myAxios.request({
            method:'get',
            url:'/user',
        }).then(
            res=>{ console.log(res.data.name); }
        )

  六、axios拦截器
  拦截操作就是在axios进行操作之前进行一些系统需要统一处理的操作,比如可以验证用户、检查请求的合法性、检查数据的完整性等等。

        Mock.mock('http://127.0.0.1:1234/user',{            
                        'name':'JavaScript'             
        })

        const myAxios=axios.create({
            baseURL:"http://127.0.0.1:1234",
            timeout: 2000,
            headers: {'X-Custom-Header': 'foobar'}            
        });

        myAxios.interceptors.request.use(
            request=>{
                console.log("检查请求...");
                return request
            }
        )

        myAxios.interceptors.response.use(
            response=>{
                console.log("检查返回数据...");
                return response
            }
        )

        myAxios.request({
            method:'get',
            url:'/user',
        }).then(
            res=>{ console.log(res.data.name); }
        )

  上面执行的结果显示如下:

检查请求...
检查返回数据...
JavaScript
02-19 06:18