Skip to content

fetch、axios

1、异步请求-铺垫

回顾http

http是超文本传输协议,规定了客户端与服务端如何通信,有两部分组成,请求和响应

请求包括,请求头,请求行,请求体

响应包括,响应头,相应行,响应体

请求头参数:user-agent、content-type、token、headers、cookie

响应头:content-type 告诉浏览器如何解析数 、etag、last-modified、 Cache-Control...

请求行/响应行:请求方式method、请求地址url、状态码status

请求体:请求参数

响应体:响应的数据

准备2:留心事项

明确:[form标签] 默认提交数据,通过enctype="application/x-www-form-urlencoded"来声明编码

  • 思考1:如果编码随便乱写 也即是 enctype="aaaaaa" 会怎么样
  • 回答1:后端收不到数据,就好比全球领导人大会,可能大家都用英语或者汉语 但是你说日语大家就搞蒙了,没按规定的来。

回答2:后期根据接口文档来 ,否则后端报错参数有误

思考3:后端接受不到参数如何排错?

回答:

text
f12打开network看请求体是否传递参数
没传数据:前端
传了数据:编码
application/x-www-form-urlencoded   对应编码格式: '参数名=值&....&参数名=值'  Qs.stringify(JS对象)
application/json	对应编码格式: '{"参数名":"值",...,"参数名":"值"}'   JSON.stringify(JS对象)

2、fetch 异步请求

fetch简介

概念说明:fetch是ecma国际化组织基于promise开发http api ,用来代替xhr

fetch语法

fetch函数类型,有两个实参

  • 第一个实参:请求地址必写
  • 第二个实参:对象类型选写

第二个实参里面的键是固定的

  • method字符串
  • headers对象类型
    • 请求头藏接口请求参数token
    • 请求头请求数据编码
  • body键声明post请求参数(根据content-type来决定数据传递格式
text
post请求传递字符串类型
'Content-Type': 'application/x-www-form-urlencoded'
需要使用Qs.stringify()把对象转化为参数字符串的形式

post请求传递JSON数据类型
'Content-Type': 'application/json'
使用JSON.stringify()把对象转化为Json形式

使用Qs.stringify()需要引入qs库

html
<script src="https://unpkg.com/qs@5.2.0/dist/qs.js"></script>

语法返回:fetch函数调用完毕返回promise

  • 第一个resresponse对象,留心并不是接口数据,如果你想获取接口数据调用response对象的json方法可以获取接口数据
text
第一个res   response对象
第二个res   接口数据

get请求

js
fetch(请求地址?参数名=&...&参数名=值, {
    method:'get',
    headers:{
        token:'xxxxxxxxxx'
    }
})
.then(res => res.json())
.then(res => console.log(res))

post请求

针对post请求传递字符串类型

js
fetch(请求地址, {
    method: 'post',
    headers: {
        'token': '用户登录成功的身份标识',
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    //body: '参数名=值&.....&参数名=值'   	//body的普通写法
    body: Qs.stringify({参数名:值,...,参数名:值})
})
.then(res => res.json())
.then(res => console.log(res))

post请求传递JSON数据类型

js
fetch(请求地址, {
    headers: {
        'token': '用户登录成功的身份标识',
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        参数名: '数据',
        参数名: '数据'
    })
   // body: '{"参数名":"参数名值", .., "参数名":"参数名值"}'  //body普通写法

})
.then(res => res.json())
.then(res => console.log(res))

3、axios 异步请求

简介

  • 概念:Axios 是一个基于 promise 的 HTTP 库(http api),可以用在浏览器和 node.js 中。
  • 原理:axios底层会判断你是浏览器环境(xhr+promise)、还是node环境(http.get/post)
  • 留心
text
【民间】axios是基于 function + ajax xhr + promise 封装、node环境 http.get/post
【官网】fetch是基于promise封装代替xhr的

使用axios需要引入库或npm下载

地址:

html
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

语法

说明

axios可以当【函数】使用、也可以当【对象】使用,还可以n种操作

axios使用(方法):有一个实参对象类型必须,里面有固定的键

  • method字符串
  • headers对象类型
  • data也是根据请求方式确定类型
  • timeout请求超时等等

axios使用(对象):axios.HTTP请求动词(实参待会说)

axios返回(promise对象),直接通过.then获取接口数据

但是第一次then返回的HTTP相关信息、接口数据在data键中,因此需要写res.data才能获取接口数据。推荐优化.then(res => res.data).then(res=> res)

1.axios函数(较多)

get

js
axios({
    //方法1
    url: '请求地址?参数名=值',
    //方法2
    url: '请求地址',
    method: 'get',
    headers: {}
    params: {
    	参数名:值,
    	//...
	}
     //...
})
.then(res=>res.data)
.then(res=>console.log(res))

post

参数为字符串

js
axios({
    url: '地址',
    method: 'post',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    //data:'参数名=数据&....&参数名=数据', 
    data:Qs.stringify({
        参数名:数据,
        //...
    })
})
.then(res=>res.data)
.then(res=>console.log(res))

参数为json

js
axios({
    url: '地址',
    method: 'post',
    headers: {
        'Content-Type': 'application/json'
    },
    //data:'{"参数名"=数据&....&"参数名"=数据}', 
    data:JSON.stringify({
        参数名:数据,
        //...
    })
})

2.axios对象(较少)

get/delete:两个参数

  • 第一个:请求地址
  • 第二个:配置对象,包括headers、params等
js
axios.get/delete(地址,{
    headers:{},
	params:{}
})
.then(res=>res.data)
.then(res=>console.log(res))

post/put:三个参数

  • 第一个:请求地址
  • 第二个:接口参数,类型根据数据编码决定
  • 第三个:可选配置对象
js
axios.post/put(
    "请求地址",
    Qs.stringify({请求参数: 值,...请求参数: 值}),  
    {
        headers: {
            token: "xxxxxxx",
            "content-type":"application/x-www-form-urlencoded",
        },
    }
)
.then((res) => res.data)
.then((res) => console.log(res))

留心:fetch默认数编码是text/pain axios编码默认 application/x-www-form-urlencoded

3.axios全局配置(较多)

全局配置axios属性后,后期发送请求前baseURL+url = 最终的请求地址

token,content-type在请求中就不用再写了

html
<script>
    axios.defaults.baseURL = 'http://kg.zhaodashen.cn/';      // 后期发送请求前baseURL+url = 最终的请求地址
	axios.defaults.headers['token'] = 'adf7cbdcdc62b07d94f86339e5687ca51';
	axios.defaults.headers['content-type'] = 'application/x-www-form-urlencoded';
    
    //....
    axios.get( "mt/admin/roles/index.jsp")
        .then((res) => res.data)
        .then((res) => (this.getData = res.data))
    
    axios.post(
        "mt/admin/roles/create.jsp",
        Qs.stringify({
            role_name: this.role_name,
        })
    )
        .then((res) => res.data)
        .then((res) => console.log(res))
</script>

4.axios实例(重要)

相当于语法1、语法2、语法3的结合体

js
const request = axios.create({
     baseURL: 'http://kg.zhaodashen.cn',
     timeout: 5000,			//请求时间仅限5秒,超过时间自动取消请求
     headers: {
        "content-type": "application/x-www-form-urlencoded",
     }
    // ....
}) 

// 留心:后期所有操作都用request来
// 否则:如果你没用request而是用axios就导致全局配置白写了
request(可选配置对象)
request.get/post(请求地址,可选配置对象)

5.axios拦截器 !!!

js
// 添加请求拦截器(先准备再发送)
// 作用:统一加loading、token、content-type等等
axios/request.interceptors.request.use(
    config=>{
        // 在发送请求之前做些什么
        // config.headers.token = 'dfadsfsdf'
        return config;
    },
    error=> {
        // 对请求错误做些什么
        return Promise.reject(error);
    });
js
// 添加响应拦截器(先判断响应的数据再交给then)
// 作用:统一关闭loading、错误处理(也就意味着以后写请求catcha不用
axios/request.interceptors.response.use(
    response=> {
        // 对响应数据做点什么 因此loading、统一接口错误处理等
        return response;
    },
    error=>{
        // 对响应错误做点什么
        return Promise.reject(error);
    });

6.axios并发控制(原理:Promise.all

js
axios.all([promise, ...]).then(res => console.log(res)).catch(err=>console.log(err))

axios取消请求

  • 语法
js
const controller = new AbortController();
const { signal } = controller;
fetch(..., {signal})

controller.abort()

.catch(e => {
  e.name === "AbortError"
});

------------

source = axios.CancelToken.source();

method: ''
headers: {},
cancelToken: source.token,  请求的时候携带标识


source.cancel('Operation canceled by the user.');

.catch(err => {
		axios.isCancel(err)
})
  • 代码
html
<div id="root">
    <h1>角色列表</h1>
    <button @click="getRolesFn">点击获取</button>
    <ul>
        <li v-for="item in roles">
            {{item.role_id}}
            {{item.role_name}}
        </li>
    </ul>

    <h1>角色创建</h1>
    <input type="text" v-model="role_name">
    <button @click="postRolesFn">点击创建</button>
</div>
<script src="http://unpkg.zhimg.com/vue"></script>
<script src="https://unpkg.com/qs@6.11.0/dist/qs.js"></script>
<script src="https://unpkg.com/axios@0.27.2/dist/axios.min.js"></script>
<script>
// // 1 生成取消请求标识
// this.source = axios.CancelToken.source()
// headers:{},
// cancelToken: this.source.token

// // 2 判断是否生成过source
// if (this.source) {
//     this.source.cancel('取消请求')
//     this.source = null
// }


const request = axios.create({
    baseURL: 'http://kg.zhaodashen.cn/mt/admin/',
    timeout: 5000,
    headers: {
        'content-type': 'application/x-www-form-urlencoded'
    }
})

const vm = new Vue({
    el: "#root",
    data: {
        roles: [],
        role_name: '',
        source: null 
    },
    methods: {
        postRolesFn() {
            request({ 
                url: 'roles/create.jsp',
                method: 'post',

                headers: {
                    token: '9201591ba0eb36c8abaea2854274f5082'
                },

                data: Qs.stringify({role_name: this.role_name})
            })
            .then(res => res.data)
            .then(res => {
                if (res.meta.state === 201)
                {
                    this.getRolesFn()
                } else {
                    alert(res.meta.msg)
                }
            })
        },
        getRolesFn() {

            // 1-this.source假的判断不走, 去生成this.source  并且请求的时候也携带了
            // 2-this.source真的 取消请求并且清空 ,  重新生成

            // 2 判断是否生成过source
            if (this.source) {
                this.source.cancel('取消重复请求')
                this.source = null
            }
            
            // 1 生成取消请求标识
            this.source = axios.CancelToken.source()
            request({
                url: 'roles/index.jsp',
                method: 'get',

                headers: {
                    token: '9201591ba0eb36c8abaea2854274f5082'
                },
                cancelToken: this.source.token,

                params: {}
            })
            .then(res => res.data)
            .then(res => {
                this.roles = res.data
            })
        },
    }
})
</script>

request封装

js
import axios from "axios"
import { Loading, Message } from "element-ui"

//创建resquest实例
const request = axios.create({
    baseURL: "/api",
    headers: {
        "content-type": "application/x-www-form-urlencoded",
    },
    timeout: 5000,
})


let loadingInstance = null
let count=0

request.interceptors.request.use(
    count++
    (config) => {
        loadingInstance = Loading.service({ fullscreen: true })
        let token = localStorage.getItem("token")
        config.headers.token = token
        return config
    },
    (err) => {
        return Promise.reject(err)
    }
)

request.interceptors.response.use(
   	count--
 
    (response) => {
        // 处理多个请求只显示一个loading
        if(!count&&loadingInstance) loadingInstance.close()
        
        if (response.data.meta.state == 403) {
            Message.error("无权访问,跳转中...")
            router.push("/login")
            return
        }

        if (response.data.meta.msg.includes("TOKEN过期")) {
            Message.error("TOKEN过期,请重新登录...")
            router.push("/login")
            // TODO. 调用store去清除登录数据
            return
        }

        return response.data
    },
    (err) => {
        return Promise.reject(err)
    }
)

export default request

MIT Licensed