Axios

295 阅读10分钟

HTTP请求报文

  1. 请求行 格式:method url
    例如:GET/product_detail?id=2 或 POST/login

  2. 请求头(一般有多个) Host:url地址
    Cookie:BAIDUID=...
    Content-Type:....或者application/json

  3. 请求体 username=tom&pwd=123
    {"username":"tom","pwd":123}

常见的响应状态码

image.png

请求方式与请求参数

一般发送4种请求方式,分别对应着:增删改查

GET(索取):从服务器端读取数据 ---查(R)
POST(交差):向服务器端添加新数据---增(C)
PUT:更新服务器端已存在的数据---改(U)
DELETE:删除服务器端数据---删(D)

请求参数

  1. query参数(查询字符串参数)
  • 参数包含在请求地址中,格式为:/xxxx?name=tom&age=18
  • 敏感数据不要用query参数,因为参数是地址的一部分,比较危险。
  • 备注:query参数又称【查询字符串参数】,编码方式为urlencoded
  1. params参数
  • 参数包含在请求地址中,格式为:http://localhost3000/add_person/tom/18
  • 敏感数据不要用params参数,因为参数是地址的一部分,比较危险。
  1. 请求体参数
  • 参数包含在请求体中,可以通过浏览器开发工具查看
  • 常用的两种格式 1.urlencoded格式
    例如:name=tom&age=18
    对应请求头:Content-Type:application/x-www-form-urlencoded

2.json格式
例如:{"name":"tom","age":12}
对应请求头:Content-Type:application/json

注意:

  • GET请求不能携带请求体参数,因为GET请求没有 请求体。
  • 理论上,一次请求可以随意使用上面3种类型参数中的任何一种,甚至一次请求的3个参数可以用3种形式携带,但是不推荐!!!
  • 一般form表单发送post请求时,自动使用请求体参数,用urlencoded编码。

API

  1. REST API(restful风格的API)
  • 发送请求进行CRUD(增删改查)哪个操作,由请求方式来决定
  • 同一个请求路径,可以进行多个操作
  • 请求方式会用到GET/POST/PUT/DELETE
  1. 非REST API(restless风格的API)
  • 请求方式不能决定请求的CRUD操作
  • 一个请求路径只对应一个操作
  • 一般只有GET/POST

json_server的使用

安装:npm i json-server -g

快速创建数据并搭建服务器:json-server __名字.json__

http请求与ajax请求

  1. ajax请求是一种特别的http请求
  2. 对服务器端来说,没有任何区别,区别是在浏览器端
  3. 浏览器端发请求:只有XHR或fetch发出的才是ajax请求,其他所有的都是非ajax请求
  4. 浏览器端接收到响应
  • 一般请求:浏览器一般会直接显示响应体数据,也就是我们时常说的自动刷新/跳转页面
  • ajax请求:浏览器不会对界面进行任何更新操作,只是调用监视的回调函数并传入响应相关数据

axios

是一个ajax请求库,vue推荐axios发ajax请求。

  • 他是基于promise的异步ajax请求库
  • 浏览器端/node端都可以使用
  • 支持请求/响应拦截器
  • 支持请求取消
  • 请求/响应数据转换
  • 批量发送多个请求

axios的get请求

1.引入axios.min.js

2.书写代码
<button id = "btn1">获取个人信息</button>

const btn1 = document.getElementById('btn1')

btn1.addEventListener('click',()=>{
    axios({
        url:'请求地址',
        method:'GET', //请求方式
    }).then(
        //axios推荐成功的回调是response,而不是value
        response =>{
            console.log('请求成功了',response.data)
        },
        error =>{
            console.log('请求失败了',error)
        }
    )
})
  • axios调用的返回值是一个Promise实例,也就是有then回调
  • 成功的值叫response,失败的值叫error
  • axios的成功的值是一个aixos封装的response对象,服务器返回的真正数据在response.data

image.png

axios发送其他请求

精简版的axios:

axios.get('url地址').then(
    response => {
        console.log('成功啦',response.data)
    },
    error => {
        console.log('失败啦',error)
    }
)

快捷让服务器延迟一会儿发送数据的方式:axios.get('http://localhost:5000/test1?delay=2000')

axios有自己默认的超时时间:30秒,你要是设置的延迟时间太长了,超过30秒,axios直接把数据丢了。

精简版的不能设置超时时间,要用完整版的

axios({
    url:'http://localhost:5000/test?dealy=5000',
    method:'GET',
    timeout:2000,设置超时时间
})

延迟时间5秒,大于了超时时间2秒,此时axios会报错,说你超时了。因为axios返回的error信息很详细。

例题1

查询

<input id = "person_id">

const btn2 = document.querySelector('#btn2')
const personId = document.querySelector('#person_id')

btn2.addEventListener('click',()=>{
    axios({
        url:'http://localhost:5000/person',
        method:'GET',
        
        //设置query参数,要用params参数!!!
        params:{id:personId.value}
        
        //设置param参数,axios是没有配置项的,直接要在url上写
        
        
    }).then(
        response=>console.log(response.data)
        error=>console.log(error)
    )
})

携带query参数时,编写的配置项是:params:...
携带param参数时,axios没有为我们提供,直接写在url上即可。

精简版:

axios.get('http://localhost:5000/person',{
    params:{id:personId.value}
}).then(
    
)

精简版的携带参数,需要在第二个参数中书写{params:{...}}

例题2

添加一个人

const personId = document.querySelector('#personId')

const personName = document.querySelector('#personName')

const personAge = document.querySelector('#personAge')

btn3.addEventListener('click',()=>{
    axios({
        url:'http://localHost:5000/person',
        method:'POST',
        
        //POST用请求体来携带参数,用的data
        data:{
            name:personName.value,
            age:personAge.value,
        }
    }).then(
        response=>
        error=>
    )
})

请求体的配置项:data:{key:value,...},这里请求体默认编码是:JSON编码

请求体携带urlencoded编码:要用模板字符串自己拼接

data:`name=${personName.value}&age=${personAge.age}`
  1. 精简版:JSON编码
axios.post('http://localhost:5000/person',{
    name:personName.value,
    age:personAge.value
}).then(
    
)

请求体中携带的json直接写参数就行,不用和query一样,还需要{params:{}}

  1. 精简版:urlencoded编码
axios.post('http://localhost:5000/person',`
    name=${personName.value}&age=${personAge.value}
`)
例题3

修改一个人

btn.addEventListener('click',()=>{
    axios({
        url:'',
        method:'PUT',
        //put是放请求体的
        data:{
            id:person_update_id.value,
            name:person_update_name.value,
            age:person_updaet_age.value
        }
        
    }).then(
        response=>
        error=>
    )
})

精简版:

axios.put('url',{
    id:person_update_id.value,
    name:person_update_name.value,
    age:person_updaet_age.value
}).then(
    response=>
    error=>
)

例题4

删除一个人

btn5.addEventListener('click',()=>{
    axios({
        //DELETE携带的是params
        url:`http://localhost:5000/person/${personDeleteId.value}`,
        method:'DELETE',
        
    }).then(
        response=>
        error=>
    )
})

特别注意:DELETE携带的是【params参数】,需要直接写在url中,并且以【模板字符串】来传入携带的参数!!!

axios常用配置项

btn.addEventListener('click',()=>{
    axios({
        url:'http://localhost:5000/person',//请求地址
        method:'GET',//请求方式
        params:{a:1,b:2},//配置query参数
        data:{c:3,d:4},//配置请求体参数,JSON编码
        data:`e=${}&f=${}`,//配置请求体参数,urlencoded编码
        timeout:2000,//配置超时时间
        params:{delay:3000},//配置query参数顺便配置延迟时间
        headers:{demo:123},//配置请求头
        responseType:'json',//配置响应数据格式,默认就是json,可以不用配
    }).then(
        response=>console.log('成功了',response.data)
        error=>console.log('失败了',error)
    )
})

responseType:'json';配置响应数据格式,默认是json,如果不配置的话,你的数据如果是其他的,会自动转换为字符串形式,如果你写死了json,那么如果不是json数据,返回的就是null

给axios配置默认值,这样对每个请求就不用一个一个在设置了

axios.defaults.timeout = 2000

//headers经常配置token,代表管理员,如果你没有这个头,就不可以进行操作
axios.defaults.headers = {token:'...'}

//配置请求的通用路径!!!
axios.defaults.baseURL = 'http://localhost:5000'


axios({
    url:'/persons',//省略请求的 通用地址
    method:'GET',
    
})

axios.create方法

因为我配置了axios的默认公共地址,但是如果我又有了一个和公共地址完全不一致的axios请求,那么再给他配置url的时候就会出错,因为他会自动帮你加上公共的地址,然后再加上你写的地址。因为都是同一个axios对象。

我想,要是再有一个axios多好,现在可以通过axios.create来实现!

//又创建了一个axios2,最好放在axios默认配置的上方
const axios2 = axios.create({
    timeout = 2000,
    //headers = {name:'tom'},
    
    baseURL = 'http://api.apiopen.top'
})

axios.defaults.timeout = 2000
aioxs.defaults.headers = {...:...}
axios.defaults.baseURL = '...'

btn3.onclick = ()=>{
    axios2({
        url:'/getJoke',
        method:'GET'
    }).then(
        response=>...
        error=>...
    )
}

请求头最好不要乱修改,容易被当做是非法入侵,要和后端协商好才可以。

axios.create(config)总结

  • 根据指定配置,创建一个新的axios,也就是每个新的axios都有他自己的配置。
  • 新axios只是没有取消请求批量发请求的方法,其他所有语法都是一样的
  • 因为项目中有些接口需要的配置和另一部分接口需要的配置不太一样,所以诞生了axios.create

axios请求拦截器

请求拦截器:在发送请求之前,做一些事情

语法:
axios.interceptor.request.use((config)=>{...})

请求拦截器里的函数,存储的是发送请求中包含的配置数据(config),然后对这些配置进行操作,最终再返回出去。

image.png


//使用 请求拦截器,本质是一个函数,参数config是请求的配置信息
axios.interceptor.request.use((config)=>{
    
    //加一些特殊的请求头,给headers加一个token:abc
    config.headers.token = 'abc'
    
    return config
})


btn.onclick = ()=>{
    axios({
        url:'http://localhost:5000/persons',
        method:'GET'
    }).then(
        response=>console.log('成功',response.data)
        error=>console.log('失败',error)
    )
}

请求拦截器必须接收到一个【请求配置】,并且最后要return出去。

请求拦截器总结

  1. 他是在真正发送请求之前,执行的一个回调函数
  2. 对所有的请求做出统一的管理:追加请求头、追加参数、界面loading提示等等。

axios响应拦截器

响应拦截器用的更多,格式:
axios.interceptor.response.use((config)=>{...})

  • 响应拦截器是:得到响应之后执行的一个回调函数(此时还没有执行then的成功/失败的回调)
  • 如果请求成功,对成功的数据进行处理
  • 如果请求失败,对失败进行进一步操作

先调用响应拦截器,再调用then的成功/失败的回调!!!

响应拦截器返回的是:axios封装的响应对象(和axios中返回的response一样),其中data就在里面。

image.png

//响应拦截器
axios.interceptor.response.use(
    response=>{
       console.log('响应拦截器成功的回调了',response)
       return response.data
    },
    error=>{
       console.log('响应拦截器失败的回调了',error) 
       return new Promise(()=>{})
    }
)

btn.onclick = async()=>{
        const result = await axios.get('...')
        console.log(result)
    }
}

我再响应拦截器成功后,直接返回return response.data,以后我再axios中成功的回调中,就不需要再返回了。老方便啦。

如果相应拦截器中没有返回值,那么就会走then中的成功回调,和.then回调是一样的道理。

再响应拦截器失败后,会输出失败的回调,并且返回return new Promise(()=>{})直接中断Promise实例,就不会再走.then中的失败回调了。

我们发现,只要写了响应拦截器,就再也不需要书写axios中的成功与失败的.then回调了。

用于:如果你是普通用户,我就会对返回的数据进行限制,如果你是高级用户,我就允许你看数据。

取消请求

CancelToken:能为一次请求“打标识”,他需要从axios对象中解构出来。

const {CancelToken} = axios
let cancel

axios({
    url:'...',
    CancelToken:new CancelToken((c)=>{
        //c是一个函数,调用c就可以关闭本次请求
        cancel = c
    })
}).then(
    response=>
    error=>
)

btn.onclick =()=>{
    cancel()
}

取消请求与拦截器

我希望能够设计出:用户不想要返回的错误,和真正响应出的错误,而不是所有的错误都在error中输出。

axios提供了一个isCancel(error)来实现

只请求一次,如果已经请求过一次了,那么就自动取消请求。

let cancel
let {CancelToken,isCancel} = axios

btn.onclick = aysnc()=>{
    //如果cancel有值,说明发了一次请求,因为CancelToken会打标识
    if(cancel){
        cancel()
    }
    axios({
        method:'GET',
        url:'...',
        CancelToken:new CancelToken((c)=>{
            cancel = c
        })
    }).then(
        response=>
        error=>{
            if(isCancel(error)){
                //如果进入判断,证明是用户取消的请求
                console.log('用户取消了请求',error.message)
            }else{
                console.log('失败了',error)
            }
            
        }
    )
}

btn2.onclick =()=>{
    cancel('我不要数据了')
}

配合拦截器去使用

const {CancelToken,isCancel} = axios
let cancel

axios.interceptor.request.use((config)=>{
    if(cancel){
        cancel()
    }
    config.cancelToken = new CancelToken((c)=>{
        cancel = c
    })
    return config
})

axios.interceptor.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('...')
}

btn.onclick =()=>{
    cancel('...')
}

批量发送请求

同时发多次请求

axios.all(里面存的axios数组)

btn.onclick =async()=>{
    axios.all([
        axios.get('')
        axios.get('')
        axios.get('')
    ]).then(
        response=>response.data
        error=>error.message
    )
}

就算其中一个延迟了3秒,最后也是一块返回出来!