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:后端接受不到参数如何排错?
回答:
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来决定数据传递格式)
post请求传递字符串类型
'Content-Type': 'application/x-www-form-urlencoded'
需要使用Qs.stringify()把对象转化为参数字符串的形式
post请求传递JSON数据类型
'Content-Type': 'application/json'
使用JSON.stringify()把对象转化为Json形式使用Qs.stringify()需要引入qs库
<script src="https://unpkg.com/qs@5.2.0/dist/qs.js"></script>语法返回:fetch函数调用完毕返回promise
- 第一个res是response对象,留心并不是接口数据,如果你想获取接口数据调用response对象的json方法可以获取接口数据
第一个res response对象
第二个res 接口数据get请求
fetch(请求地址?参数名=值&...&参数名=值, {
method:'get',
headers:{
token:'xxxxxxxxxx'
}
})
.then(res => res.json())
.then(res => console.log(res))post请求
针对post请求传递字符串类型
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数据类型
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)
- 留心
【民间】axios是基于 function + ajax xhr + promise 封装、node环境 http.get/post
【官网】fetch是基于promise封装代替xhr的使用axios需要引入库或npm下载
地址:
<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
axios({
//方法1
url: '请求地址?参数名=值',
//方法2
url: '请求地址',
method: 'get',
headers: {}
params: {
参数名:值,
//...
}
//...
})
.then(res=>res.data)
.then(res=>console.log(res))post
参数为字符串
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
axios({
url: '地址',
method: 'post',
headers: {
'Content-Type': 'application/json'
},
//data:'{"参数名"=数据&....&"参数名"=数据}',
data:JSON.stringify({
参数名:数据,
//...
})
})2.axios对象(较少)
get/delete:两个参数
- 第一个:请求地址
- 第二个:配置对象,包括headers、params等
axios.get/delete(地址,{
headers:{},
params:{}
})
.then(res=>res.data)
.then(res=>console.log(res))post/put:三个参数
- 第一个:请求地址
- 第二个:接口参数,类型根据数据编码决定
- 第三个:可选配置对象
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在请求中就不用再写了
<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的结合体
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拦截器 !!!
// 添加请求拦截器(先准备再发送)
// 作用:统一加loading、token、content-type等等
axios/request.interceptors.request.use(
config=>{
// 在发送请求之前做些什么
// config.headers.token = 'dfadsfsdf'
return config;
},
error=> {
// 对请求错误做些什么
return Promise.reject(error);
});// 添加响应拦截器(先判断响应的数据再交给then)
// 作用:统一关闭loading、错误处理(也就意味着以后写请求catcha不用
axios/request.interceptors.response.use(
response=> {
// 对响应数据做点什么 因此loading、统一接口错误处理等
return response;
},
error=>{
// 对响应错误做点什么
return Promise.reject(error);
});6.axios并发控制(原理:Promise.all
axios.all([promise, ...]).then(res => console.log(res)).catch(err=>console.log(err))axios取消请求
- 语法
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)
})- 代码
<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封装
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