axious

278 阅读11分钟

axios教程

第1章:HTTP相关

1.1. MDN文档

developer.mozilla.org/zh-CN/docs/…

1.2. HTTP请求基本过程

image.png 1.     浏览器端向服务器发送HTTP请求(请求报文)

2.     后台服务器接收到请求后,处理请求, 向浏览器端返回HTTP响应(响应报文)

3.     浏览器端接收到响应, 解析显示响应体调用回调函数

1.3. HTTP请求报文

1. 请求行:

格式:method url

例如:GET /product_detail?id=2   或  POST /login

2. 请求头(一般有多个请求头)

Host: www.baidu.com

Cookie: BAIDUID=AD3B0FA706E; BIDUPSID=AD3B0FA706;

Content-Type: application/x-www-form-urlencoded 或者 application/json

3. 请求体

username=tom&pwd=123

{"username": "tom", "pwd": 123}

1.4. HTTP响应报文

1. 响应行:

格式:status statusText

例如:200 OK  或  404 Not Found

2. 响应头(一般有多个)

Content-Type: text/html;charset=utf-8

Set-Cookie: BD_CK_SAM=1;path=/

3. 响应体

html/json/js/css/图片...

1.5. 常见的响应状态码

200  OK                   请求成功。一般用于GET与POST请求

201  Created               已创建。成功请求并创建了新的资源

401  Unauthorized          未授权/请求要求用户的身份认证

404  Not Found             服务器无法根据客户端的请求找到资源

500  Internal Server Error     服务器内部错误,无法完成请求

1.6. 请求方式与请求参数

1.   请求方式

1.      GET(索取): 从服务器端读取数据 ----- 查(R)

2.      POST(交差): 向服务器端添加新数据 ------ 增(C)

3.      PUT: 更新服务器端已存在的数据 ------- 改(U)

4.      DELETE: 删除服务器端数据 ---------删(D)

2. 请求参数

1. query 参数(查询字符串参数)****

  1. 参数包含在请求地址中,格式为:/xxxx?name=tom&age=18

  2. 敏感数据不要用query参数,因为参数是地址的一部分,比较危险。

  3. 备注:query参数又称查询字符串参数,编码方式为urlencoded

2. params 参数****

1.    参数包含在请求地址中,格式如下:

http://localhost:3000/add_person /tom/18

2.敏感数据不要用params参数,因为参数是地址的一部分,比较危险。

3. 请求体参数****

1.参数包含在请求体中,可通过浏览器开发工具查看

2.常用的两种格式:

格式一:urlencoded格式

例如:name=tom&age=18

对应请求头:Content-Type: application/x-www-form-urlencoded

格式二:json格式

例如: {"name": "tom", "age": 12}

              对应请求头:Content-Type: application/json

特别注意:****

1.      GET请求不能携带请求体参数,因为GET请求没有请求体。

2.      理论上一次请求可以随意使用上述3种类型参数中的任何一种,甚至一次请求的3个参数可以用3种形式携带,但一般不这样做。

3.      一般来说我们有一些“约定俗成”的规矩:
(1) 例如form表单发送post请求时: 自动使用请求体参数,用urlencoded编码。

(2) 例如jQuery发送ajax-post请求时:自动使用请求体参数,用urlencoded编码。

4.      开发中请求到底发给谁?用什么请求方式?携带什么参数?----要参考项目的API接口文档。

第2章:API相关

2.1. API的分类

1. REST API ( restful 风格的API )

①    发送请求进行CRUD哪个操作由请求方式来决定

②    同一个请求路径可以进行多个操作

③    请求方式会用到GET/POST/PUT/DELETE

2. 非REST API ( restless风格的API )

④    请求方式不决定请求的CRUD操作

⑤    一个请求路径只对应一个操作

⑥    一般只有GET/POST

2.2. 使用json-server搭建REST API

2.2.1. json-server是什么?

用来快速搭建REST API的工具包

2.2.2. 使用json-server

1.     在线文档: github.com/typicode/js…

2.     下载: npm install -g json-server

3.     目标根目录下创建数据库json文件: db.json

      

  {

          "posts": [

            { "id": 1, "title": "json-server", "author": "typicode" }

          ],

          "comments": [

            { "id": 1, "body": "some comment", "postId": 1 }

          ],

          "profile": { "name": "typicode" }

        }

4.     启动服务器执行命令: json-server --watch db.json

2.2.3. 使用浏览器访问测试

http://localhost:3000/posts

http://localhost:3000/posts/

2.2.4. 使用postman测试接口

测试GET/POST/PUT/DELETE请求

image.png

2.2.5. 一般http请求与ajax请求

1.     ajax请求是一种特别的http请求

2.     对服务器端来说, 没有任何区别, 区别在浏览器端

3.     浏览器端发请求: 只有XHR或fetch发出的才是ajax请求, 其它所有的都是非ajax请求

4.     浏览器端接收到响应

(1)   一般请求: 浏览器一般会直接显示响应体数据, 也就是我们常说的自动刷新/跳转页面

(2)   ajax请求: 浏览器不会对界面进行任何更新操作, 只是调用监视的回调函数并传入响应相关数据

第3章:axios的理解和使用

3.1. axios是什么?

1.     前端最流行的ajax请求库

2.     react/vue官方都推荐使用axios发ajax请求

3.     文档: github.com/axios/axios

3.2. axios特点

1.     基于promise的异步ajax请求库

2.     浏览器端/node端都可以使用

3.     支持请求/响应拦截器

4.     支持请求取消

5.     请求/响应数据转换

6.     批量发送多个请求 

3.3. 使用axios发ajax请求

/* 1. GET请求: 从服务器端获取数据*/

function testGet({                                         

  axios({

    url'http://localhost:3000/posts',

    // url'http://localhost:3000/posts2',

    method'GET',

    params: {

      id1,

      xxx'abc'

    }

  }).then(

    response => {

      console.log(response.data, response.status, response.statusText)

    },

    error => {

      alert(error.message)

    }

  )

}

/* 2. POST请求: 服务器端保存数据*/

function testPost() {

  axios({

    url'http://localhost:3000/posts',

    method'POST',

    data: {

      "title""json-server---", 

      "author""typicode---"

    }

  }).then(

    response => {

      console.log(response.data)

    },

    error => {

      alert(error.message)

    }

  )

}

/* 3. PUT请求: 服务器端更新数据*/

function testPut() {

  axios({

    url'http://localhost:3000/posts/1',

    method'put',

    data: {

      "title""json-server+++", 

      "author""typicode+++"

    }

  }).then(

    response => {

      console.log(response.data)

    },

    error => {

      alert(error.message)

    }

  )

}

/* 2. DELETE请求: 服务器端删除数据*/

function testDelete() {

  axios({

    url'http://localhost:3000/posts/6',

    method'delete'

  }).then(

    response => {

      console.log(response.data)

    },

    error => {

      alert(error.message)

    }

  )

}

3.4     axios的基本使用和配置项

       

1.axios调用的返回值是Promise实例。

2.成功的值叫response,失败的值叫error。

3.axios成功的值是一个axios封装的response对象,服务器返回的真正数据在response.data中

4.携带query参数时,编写的配置项叫做params

5.携带params参数时,就需要自己手动拼在url中

//获取所有人---发送GET请求---不携带参数
btn1.onclick = ()=>{
        //完整版
        /* axios({
                url:'http://localhost:5000/persons', //请求地址
                method:'GET',//请求方式
        }).then(
                response => {console.log('请求成功了',response.data);},
                error => {console.log('请求失败了',error);}
        ) */

        //精简版
        axios.get('http://localhost:5000/persons').then(
                response => {console.log('请求成功了',response.data);},
                error => {console.log('请求失败了',error);}
        )
}

//获取所某个人---发送GET请求---携带query参数
btn2.onclick = ()=>{
        //完整版
        /* axios({
                url:'http://localhost:5000/person',
                method:'GET',
                params:{id:personId.value} //此处写的是params,但携带的是query参数
        }).then(
                response => {console.log('成功了',response.data);},
                error => {console.log('失败了',error);}
        ) */

        //精简版
        axios.get('http://localhost:5000/person',{params:{id:personId.value}}).then(
                response => {console.log('成功了',response.data);},
                error => {console.log('失败了',error);}
        )
}

//添加一个人---发送POST请求---携带json编码参数 或 urlencoded编码
btn3.onclick = ()=>{
        //完整版
        /* axios({
                url:'http://localhost:5000/person',
                method:'POST',
                data:{name:personName.value,age:personAge.value}//携带请求体参数(json编码)
                //data:`name=${personName.value}&age=${personAge.value}`//携带请求体参数(urlencoded编码)
        }).then(
                response => {console.log('成功了',response.data);},
                error => {console.log('失败了',error);}
        ) */

        //精简版
        axios.post('http://localhost:5000/person',`name=${personName.value}&age=${personAge.value}`).then(
                response => {console.log('成功了',response.data);},
                error => {console.log('失败了',error);}
        )
}

//更新一个人---发送PUT请求---携带json编码参数 或 urlencoded编码
btn4.onclick = ()=>{
        //完整版
        /* axios({
                url:'http://localhost:5000/person',
                method:'PUT',
                data:{
                        id:personUpdateId.value,
                        name:personUpdateName.value,
                        age:personUpdateAge.value
                }
        }).then(
                response => {console.log('成功了',response.data);},
                error => {console.log('失败了',error);}
        ) */

        //精简版
        axios.put('http://localhost:5000/person',{
                id:personUpdateId.value,
                name:personUpdateName.value,
                age:personUpdateAge.value
        }).then(
                response => {console.log('成功了',response.data);},
                error => {console.log('失败了',error);}
        )
}

//删除一个人---发送DELETE请求---携带params参数
btn5.onclick = ()=>{
        axios({
                url:`http://localhost:5000/person/${personDeleteId.value}`,
                method:'DELETE',
        }).then(
                response => {console.log('成功了',response.data);},
                error => {console.log('失败了',error);}
        )
}

         

给axios配置默认属性

           

 axios.defaults.timeout = 2000

            axios.defaults.headers = {school:'atguigu'}

            axios.defaults.baseURL = 'http://localhost:5000'

            btn.onclick = ()=>{

                axios({

                    url:'/persons', //请求地址

                    method:'GET',//请求方式

                    //params:{delay:3000},//配置query参数

                    //data:{c:3,d:3},//配置请求体参数(json编码)

                    //data:'e=5&f=6',//配置请求体参数(urlencoded编码)

                    //timeout:2000,//配置超时时间

                    //headers:{school:'atguigu'} //配置请求头

                    //responseType:'json'//配置响应数据的格式(默认值)

                }).then(

                    response => {console.log('成功了',response.data);},

                    error => {console.log('失败了',error);}

                )

            }

3.5. axios常用语法

axios(config): 通用/最本质的发任意类型请求的方式

axios(url[, config]): 可以只指定url发get请求

axios.request(config): 等同于axios(config)

axios.get(url[, config]): 发get请求

axios.delete(url[, config]): 发delete请求

axios.post(url[, data, config]): 发post请求

axios.put(url[, data, config]): 发put请求

axios.defaults.xxx: 请求的默认全局配置

axios.interceptors.request.use(): 添加请求拦截器

axios.interceptors.response.use(): 添加响应拦截器

axios.create([config]): 创建一个新的axios(但它没有下面的功能)

axios.CancelToken(): 用于创建取消请求的token对象

axios.isCancel(): 是否是一个取消请求的错误

axios.all(promises): 用于批量执行多个异步请求

3.4.1. axios.create(config)

1.     根据指定配置创建一个新的axios, 也就就每个新axios都有自己的配置

2.     新axios只是没有取消请求和批量发请求的方法, 其它所有语法都是一致的

3.     为什么要设计这个语法?

(1)   需求: 项目中有部分接口需要的配置与另一部分接口需要的配置不太一样, 如何处理

(2)   解决: 创建2个新axios, 每个都有自己特有的配置, 分别应用到不同要求的接口请求中

3.4.2. 拦截器函数/ajax请求/请求的回调函数的调用顺序

1.     说明: 调用axios()并不是立即发送ajax请求, 而是需要经历一个较长的流程

2.     流程: 请求拦截器=> 发ajax请求 => 响应拦截器 =>请求的回调

3.4.3. 取消请求

1.     基本流程

①    配置cancelToken对象

②    缓存用于取消请求的cancel函数

③    在后面特定时机调用cancel函数取消请求

④    在错误回调中判断如果error是cancel, 做相应处理

2.     实现功能

   点击按钮, 取消某个正在请求中的请求

在请求一个接口前, 取消前面一个未完成的请求

//不带拦截器

<button id="btn">点我获取测试数据</button><br/><br/>
<button id="btn2">取消请求</button><br/><br/>
<script type="text/javascript" >
        const btn = document.getElementById('btn')
        const btn2 = document.getElementById('btn2')
        const {CancelToken,isCancel} = axios //CancelToken能为一次请求“打标识”
        let cancel

        btn.onclick = async()=>{
                if(cancel) cancel()
                axios({
                        url:'http://localhost:5000/test1?delay=3000',
                        // new一个构造函数CancelToken
                        cancelToken:new CancelToken((c)=>{ //c是一个函数,调用c就可以关闭本次请求
                                cancel = c
                        })
                }).then(
                        response => {console.log('成功了',response.data);},
                        error => {
                                // isCancel判断是用户取消了请求
                                if(isCancel(error)){
                                        //如果进入判断,证明:是用户取消了请求 ,这个error是底层封装的一个对象
                                        console.log('用户取消了请求,原因是:',error.message);
                                }else{
                                        console.log('失败了',error);
                                }
                        }
                )
        }

        btn2.onclick = ()=>{
                //cancel传入的message是内部维护的取消的消息,取消的原因
                cancel('任性,就是不要了')
        }
        
        
//带拦截器

const btn = document.getElementById('btn')
const btn2 = document.getElementById('btn2')
const { CancelToken, isCancel } = axios //CancelToken能为一次请求“打标识”
let cancel

axios.interceptors.request.use((config) => {
        if (cancel) cancel('取消了')
        config.cancelToken = new CancelToken((c) => cancel = c)
        return config
})

axios.interceptors.response.use(
        response => { return response.data },
        error => {
                if (isCancel(error)) {
                        //如果进入判断,证明:是用户取消了请求
                        console.log('用户取消了请求,原因是:', error.message);
                } else {
                        console.log('失败了', error);
                }
                return new Promise(() => { })
        }
)

btn.onclick = async () => {
        const result = await axios.get('http://localhost:5000/test1?delay=3000')
        console.log(result);
}

btn2.onclick = () => {
        cancel('任性,就是不要了')
}

axios.create方法

axios.create(config)
    1. 根据指定配置创建一个新的axios, 也就是每个新axios都有自己的配置
    2. 新axios只是没有取消请求和批量发请求的方法, 其它所有语法都是一致的
    3. 为什么要设计这个语法?
    需求: 项目中有部分接口需要的配置与另一部分接口需要的配置不太一样
    
const axios2 = axios.create({
        timeout: 3000,
        //headers:{name:'tom'},
        baseURL: 'https://api.apiopen.top'
})

//给axios配置默认属性
axios.defaults.timeout = 2000
axios.defaults.headers = { school: 'atguigu' }
axios.defaults.baseURL = 'http://localhost:5000'

btn.onclick = () => {
        axios({
                url: '/persons', //请求地址
                method: 'GET',//请求方式
                //params:{delay:3000},//配置query参数
                //data:{c:3,d:3},//配置请求体参数(json编码)
                //data:'e=5&f=6',//配置请求体参数(urlencoded编码)
                //timeout:2000,//配置超时时间
                //headers:{school:'atguigu'} //配置请求头
                //responseType:'json'//配置响应数据的格式(默认值)
        }).then(
                response => { console.log('成功了', response.data); },
                error => { console.log('失败了', error); }
        )
}

btn2.onclick = () => {
        axios({
                url: '/test1', //请求地址
                method: 'GET',//请求方式
                //timeout:2000,//配置超时时间
                //headers:{school:'atguigu'} //配置请求头
        }).then(
                response => { console.log('成功了', response.data); },
                error => { console.log('失败了', error); }
        )
}

btn3.onclick = () => {
        axios2({
                url: '/getJoke',
                method: 'GET'
        }).then(
                response => { console.log('成功了', response.data); },
                error => { console.log('失败了', error); }
        )
}

axios中的拦截器

axios请求拦截器
        1.是什么?
            在真正发请求前执行的一个回调函数
        2.作用:
            对所有的请求做统一的处理:追加请求头、追加参数、界面loading提示等等

axios响应拦截器
        1.是什么?
            得到响应之后执行的一组回调函数
        2.作用:
            若请求成功,对成功的数据进行处理
            若请求失败,对失败进行统一的操作

const btn = document.getElementById('btn')

//请求拦截器 config对象是一次请求详细的配置
axios.interceptors.request.use((config) => {
        console.log('请求拦截器1执行了');
        if (Date.now() % 2 === 0) {
                config.headers.token = 'atguigu'
        }
        return config
})

//响应拦截器
axios.interceptors.response.use(
        response => {
                console.log('响应拦截器成功的回调执行了', response);
                if (Date.now() % 2 === 0) return response.data
                else return '时间戳不是偶数,不能给你数据'
        },
        error => {
                console.log('响应拦截器失败的回调执行了');
                alert(error);
                // 中断promise链:(1)当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数。这里和.then一样						
                return new Promise(() => { })
        }
)

btn.onclick = async () => {
        // 如果表达式是Promise实例对象, await后的返回值是promise成功的值
        const result = await axios.get('http://localhost:5000/persons21')
        console.log(result);
}

axios批量发送请求

btn.onclick = async () => {
    axios.all([
            axios.get('http://localhost:5000/test1'),
            axios.get('http://localhost:5000/test2?delay=3000'),
            axios.get('http://localhost:5000/test3'),
    ]).then(
            response => { console.log(response); },
            error => { console.log(error); }
    )
}