目录
◼️ Axios的基础用法(get、post、put 等请求方法)
🌳 Axios的诞生
为什么会诞生Axios?说到Axios
我们就不得不说下Ajax
。最初的旧浏览器页面在向服务器请求数据时,由于返回的是整个页面的数据,所以整个页面都会强制刷新一下,这对于用户来讲并不是很友好。因为当我们只需要请求部分数据时,服务器返回给我们的确是整个页面的数据,这样会造成网络资源的占用,即十分消耗网络资源。为了提高数据请求效率,异步网络请求Ajax就应运而生了,它可以在页面无刷新的情况下请求数据。因此,这样一来,当我们只是需要修改页面的部分数据时,可以实现不刷新页面的功能。
🌳 Axios的介绍
定义
- Axios是一个基于promise 的 HTTP 库(类似于jQuery的Ajax,用于HTTP请求),可以用在浏览器和 node.js中(既可以用于客户端也可以用于node.js编写的服务端)。
Axios 是一个基于 promise 的网络请求库,可以用于浏览器和 node.js中。Axios(相比于原生的XMLHttpRequest对象来说) 简单易用,(相比于jQuery)axios包尺寸小且提供了易于扩展的接口,是专注于网络请求的库。
原理
- axios(ajax i/o system)不是一种新技术,本质上也是对原生XHR(XMLHttpReques)的封装,只不过它是基于Promise的,是Promise的实现版本,符合最新的ES规范。
👉 番外:AJAX
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
—— 异步网络请求 —— Ajax能够让页面无刷新的请求数据 ——
AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
AJAX 是与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下 ;通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新
实现ajax的方式有多种,如jQuery封装的ajax,原生的XMLHttpRequest,以及axios都可以实现异步网络请求。
Ajax是一种技术方案,但并不是一种新技术。它依赖现有的CSS/HTML/JavaScript,而其中最核心的依赖是浏览器提供的XMLHttpRequest对象,是这个对象使得浏览器可以发出HTTP请求与接收HTTP响应。实现了在页面不刷新个情况下和服务器进行数据交互。 异步的javascript和xml AJAX 是一种用于创建快速动态网页的技术。 ajax用来与后台交互
所以,我们现在梳理一下三者之间的关系:
参考资料:ajax与XHR的理解和使用
参考资料:原生ajax和jquery的ajax有何区别
① Ajax的实现依赖于XMLHttpRequest对象,即XMLHttpRequest可以实现Ajax。
Asynchronous JavaScript + XML(异步JavaScript和XML), 其本身不是一种新技术,而是一个在 2005年被Jesse James Garrett提出的新术语,用来描述一种使用现有技术集合‘新’方法,包括: HTML 或 XHTML, CSS,JavaScript, DOM, XML, XSLT, 以及最重要的 XMLHttpRequest。当使用结合了这些技术的AJAX模型以后, 网页应用能够快速地将增量更新呈现在用户界面上,而不需要重载(刷新)整个页面。这使得程序能够更快地回应用户的操作。
XMLHttpRequest是AJAX的基础,XMLHttpRequest API是Ajax的核心。XMLHttpRequest 用于在后台与服务器交换数据。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
② Axios在此基础上封装了XMLHttpRequest,即Axios可以实现Ajax
③ Jquery是对Javascript的一种轻量级封装的框架,而Ajax是JavaScript的一种应用,是异步JavaScript和XML——由XML+Javascript组合起来的一种异步请求技术,可实现动态局部刷新。也就是说Jquey是JavaScript的一个函数库,而JavaScript包含Ajax。 Jquery在原生Ajax的基础上进行了封装(说白了Jquey封装了Ajax,其实就是对原生XHR
的封装——做了兼容处理,简化了使用),也就是说在Jquery中可以用Ajax。
JQuery 提供了用于 AJAX 开发的丰富函数(方法)库。 通过 jQuery Ajax,使用 HTTP Get 和 HTTP Post,你都可以从远程服务器请求 TXT、HTML、XML 或 JSON。
但各种方式都有利弊:
- 原生的XMLHttpRequest的配置和调用方式都很繁琐,实现异步请求十分麻烦。
- jQuery的ajax相对于原生的ajax是非常好用的,但是没有必要因为要用ajax异步网络请求而引用整个jQuery框架。
特性
从浏览器创建 XMLHttpRequests请求
从node.js创建http请求
支持 Promise API
拦截请求和响应,比如:在请求前添加授权和响应前做一些事情。
转换请求数据和响应数据,比如:进行请求加密或者响应数据加密。
取消请求
自动转换JSON数据
客户端支持防御XSRF
浏览器支持情况
- Firefox、Chrome、Safari、Opera、Edge、IE8+
如何安装
5种安装方式
- 使用npm安装
$ npm install axios
- 使用bower安装
$ bower install axios
- 使用 yarn安装
$ yarn add axios
- 使用 jsDelivr CDN
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
- 使用 unpkg CDN
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
🌳 Axios的使用
◼️ 创建vue项目
我们以在vue中使用axios为例
在电脑硬盘里,新建项目文件夹,使用vscode打开项目文件夹,在项目文件夹下,右键选择“在集成终端中打开”,打开终端。(当然,你也可以通过在项目文件夹目录的路径地址栏中输入cmd,按回车,打开命令行窗口进行创建vue项目)
现在,我们开始创建一个vue项目:vue create axios-vue,选择自定义配置manually select features,终端显示如下:上下键切换,空格键选择对应配置。
然后,依次选择完成余下的配置
运行终端指令 cd axios-vue 、npm run serve启动项目后,运行终端指令npm install axios安装axios,至此,项目创建完成,axios安装完成。
在项目的public文件夹下新建data.json文件,用于模拟数据。在组建中引入axios,并发起请求。
项目结构,如下:
* App.vue组件
<template> <div id="app"> <img alt="Vue logo" src="./assets/logo.png"> <HelloWorld></HelloWorld> </div> </template> <script> import HelloWorld from './components/HelloWorld.vue' export default { name: 'App', components: { HelloWorld } } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
* index.html文件
<!DOCTYPE html> <html lang=""> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <link rel="icon" href="<%= BASE_URL %>favicon.ico"> <title><%= htmlWebpackPlugin.options.title %></title> </head> <body> <div id="app"></div> </body> </html>
* data.json文件
{ "title":"vue project", "create_time":"2023-02-13" }
* HelloWorld.vue组件
在组件中,引入axios并使用,就构建了一个基本的get请求,axios请求的结果无论成功与否都会返回一个promise对象,因此,接着调用then方法即可查看请求的结果了。
<template> <div class="hello">...</div> </template> <script> import axios from "axios"; export default { name: "HelloWorld", created() { axios .get("/data.json") .then((result) => { // result不是直接的返回结果 console.log(result); // result.data才是真正的返回结果 console.log(result.data); }) .catch((err) => { console.log(err); }); }, }; </script> <style scoped>...</style>
此时,已经可以请求到数据了,效果如下:
❓ 我的疑惑:
个人理解——虽然没有配置基础路径,但axios.get("/data.json"),控制台也可以请求到数据,是因为服务器是本机(我此时的电脑充当服务器),所以使用axios的get方法请求时,url可以只写请求的url,而省去基础路径http://localhost:8080。
个人理解——使用axios进行网络请求时,貌似只有get方法才能在其url参数中直接使用文件代替url,进而获取向服务器请求的文件内容,即axios.get("/data.json"),其中,data.json是一个json格式的文件,于是,可以试着尝试axios.get("/index.html")获取,index.html文件的内容,发现也是可以获取到。但是换成post请求方法,就会404 (Not Found),个人浅见,可能是因为post是用于向服务器提交数据的,而非用于获取,且目前还没有写(配置)后端接口,是以,会出现404(Not Found)
◼️ Axios的基础用法(get、post、put 等请求方法)
Axios常用的几种请求方法:get,post,put,patch,delete
- get:一般用于获取数据
- post:一般用于提交数据(表单提交与文件上传)
- patch:更新数据(只将修改的数据推送到后端(服务端))
- put:更新数据(所有数据推送到服务端)
- delete:删除数据
题外话:一般公司在实际项目开发过程中:
(1) post:一般用于新建数据
(2) put:一般用于更新数据(适合数据量比较小的更新)
(3) patch一般用于数据量较大的时候的数据更新。
比如,一个表单的数据量很大,有很多项,使用put的话,全部数据推送一次是比较耗性能 的,这个时候可以考虑用patch,只将修改的数据推送到后端。
以上这些题外话,只是一般的常规用法,不能代表一定要这样用;当然了,你可能会说我用post来获取数据,行不行?这个当然行了,答案是肯定的,绝对没问题!具体怎么用还是前后端一起商量着决定。
get方法
方式一:请求别名的使用
请求别名的方式,一种简化请求方法配置的API。
axios.get(url[, config]) 用于获取数据
- 如果不带有参数,代码如下:
<script> import axios from "axios"; export default { name: "HelloWorld", created() { axios .get("/data.json") .then((result) => { // result不是直接的返回结果 console.log("数据:",result); // result.data才是真正的返回结果 console.log("真正的数据:",result.data); }) .catch((err) => { console.log(err); }); }, }; </script>
- 如果带有参数,代码如下:
<script> import axios from "axios"; export default { name: "HelloWorld", created() { // 第一种方式:将参数直接写在url中 // 向给定ID的用户发起请求 axios .get("/data.json?id=5") .then((result) => { // 处理成功情况 console.log(result); }) .catch((err) => { // 处理错误情况 console.log(err); }); // 第二种方式:将参数直接写在params中 axios .get("/data.json", { //带参数时 ————若无参数时直接省略params对象不写 params: { id: 5, }, }) .then((result) => { // result不是直接的返回结果 console.log("数据:", result); // result.data才是真正的返回结果 console.log("真正的数据:", result.data); }) .catch((err) => { console.log(err); }); // 支持async/await用法 // axios 是一个基于 promise 网络请求库, 这意味着, 你必须使用 ES6 的 then() 或者 ES8 的 async/await 来处理 Promise 实例对象。 // 注意: 由于async/await 是ECMAScript 2017中的一部分,而且在IE和一些旧的浏览器中不支持,所以使用时务必要小心。 async function getUser() { try { const response = await axios.get("/user?ID=12345"); console.log(response); } catch (error) { console.error(error); } } }, }; </script>
此时表示,参数为id=5,最终的请求路径Request URL:http://localhost:8080/data.json?id=5
方式二:通过向axios传递相关配置来创建请求
某些时候我们可能需要对axios的配置参数进行更加详细的设置,此时通过向axios传递相关配置来创建请求,就显得更方便。
参考:axios的请求配置项有哪些 | 请求配置 | Axios 中文文档 | Axios 中文网
- 如果不带参数,代码如下:
<script> import axios from "axios"; export default { name: "HelloWorld", created() { axios({ method: "get", url: "/data.json" }).then((res) => { // result不是直接的返回结果 console.log("数据:", result); // result.data才是真正的返回结果 console.log("真正的数据:", result.data); }); }, }; </script>
- 如果带有参数,代码如下:
<script> import axios from "axios"; export default { name: "HelloWorld", created() { axios({ method: "get", url: "/data.json", //带参数时 ————若无参数时直接省略params对象不写 params: { id: 5, }, }).then((result) => { // result不是直接的返回结果 console.log("数据:", result); // result.data才是真正的返回结果 console.log("真正的数据:", result.data); }); }, }; </script>
此时表示,参数为id=5,最终的请求路径Request URL:http://localhost:8080/data.json?id=5
了解一下浏览器控制台相关的请求信息:
Request URL:请求URL
Request Method:请求方式
Status Code:状态码
Status Code:304 Not Modified
304是重定向;正常情况下,第一次访问接口的时候返回的都是200;当你第二次访问接口的时候,如果数据没有变化, 那么浏览器会自动识别返回一个状态304,代表数据没有更改 、重定向;相当于重定向到你刚刚访问的资源,这样的话会加载更快!
Request Header:请求头 ——view parsed模式
User-Agent:产生请求的浏览器类型。
Accept:客户端可识别的内容类型列表。
Host:请求的主机名。
Query String Parameters:查询字符串参数
get请求时,参数会以url string 的形式进行传递,即?后的字符串则为其请求参数,并以&做为分隔符。
附:请求头 Request Header ——view source模式——源码模式(点击view source进入)
view source和view parsed模式之间切换
在分析网页提交内容,返回的值等过程中,request header,request post data,response header等信息中有view source和view parsed两种模式,点击即可切换,方便数据分析。
比如查看用URLEncode编码之后的数据,通过view parsed可以知道”%2F”表示斜杠”/”。
post方法
post请求常用的数据请求格式有三种:
1、Content-Type : application/x-www-form-urlencoded。
ajax默认的数据格式。请求体中的数据会以json字符串的形式发送到后端。
2、Content-Type : application/json ; charset=utf-8。
axios默认的数据格式。请求体中的数据会以普通表单形式(键值对)发送到后端。
3、Content-Type : multipart/form-data 。
它会将请求体的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。
参考资料:POST请求的三种常见数据提交格式
下面,我们简单了解一下http的post请求的三种类型 👇
🌱 Content-Type:application/x-www-form-urlencoded
<template> <div class="hello">......</div> </template> <script> import axios from "axios"; import qs from 'qs'; export default { name: "HelloWorld", created() { // 对象data的属性名uname和upwd引号可加可不加 let data = {uname:"dingding",upwd:"123456"}; axios.post("/date.json",qs.stringify({ data })) .then(res=>{ console.log(res); }) }, }; </script> <style scoped> </style>
Content-Type和参数:
🌱 Content-Type: multipart/form-data(常用于表单提交(图片上传、文件上传))
<template> <div class="hello">......</div> </template> <script> import axios from "axios"; export default { name: "HelloWorld", created() { let data = {uname: "dingding", upwd: 123456}; let formData = new FormData(); for (let key in data) { formData.append(key, data[key]); } console.log(formData); axios.post("/date.json", formData).then((res) => { console.log(res.data); }); }, }; </script> <style scoped> </style>
注意:form-data类型的相关请求信息
- 请求地址Request URL: http://localhost:8080/data.json
- 请求头中Content-Type: multipart/form-data; boundary=----WebKitFormBoundarySmuEKOlBaxhc0In2
- 参数形式:{uname: "dingding", upwd: 123456}
Content-Type和参数:
🌱 Content-Type: application/json(常用)
- 方式一:请求别名的使用
axios.post(url[, data[, config]]) 用于发送数据 `data`对象是作为请求主体被发送的数据
axios发送post无参请求,代码如下:
<template> <div class="hello">......</div> </template> <script> import axios from "axios"; export default { name: "HelloWorld", created() { //把get无参请求的get改为post即可 axios.post("/data.json").then(res=>{ console.log(res) }); }, }; </script> <style scoped>...</style>
axios发送post有参请求,2种传参形式,代码如下:
① 查询字符串形式
<template> <div class="hello">......</div> </template> <script> import axios from "axios"; export default { name: "HelloWorld", created() { //发送post请求携带参数,直接使用"uname=dingding&upwd=123456" axios.post("/data.json", "uname=dingding&upwd=123456").then(res=>{ console.log(res) }); }, }; </script> <style scoped>...</style>
② 对象形式
<template> <div class="hello">......</div> </template> <script> import axios from "axios"; export default { name: "HelloWorld", created() { //发送post请求携带参数,这种传参方式后台得使用requestBody处理 axios.post("/data.json", {uname:"dingding",upwd:123456}).then(res=>{ console.log(res) }); }, }; </script> <style scoped>...</style>
- 方式二:通过向axios传递相关配置来创建请求
<template> <div class="hello">......</div> </template> <script> import axios from "axios"; export default { name: "HelloWorld", created() { let data = {uname:"dingding",upwd:123456}; axios({ method:'post', url:'/data.json', // 与get请求使用params不同的是,post请求使用data属性 data:data }).then(res=>{ console.log(res) }) }, }; </script> <style scoped>...</style>
注意:别名方式和data方式的相关请求信息
- 请求地址Request URL: http://localhost:8080/data.json,
- 请求头中Content-Type: application/json
- 参数形式:{uname: "dingding", upwd: 123456}
Content-Type和参数:
参考资料:
axios中post请求application/json和application/x-www-form-urlencoded
put和patch方法
put和patch请求与post请求用法一样类似,同样有x-www-form-urlencoded、applicition/json和form-data,只有method不同,其他相同。在此不过多赘述了,简单写一下!
let data = {uname:"dingding",upwd:123456}; // axios.put(url[, data[, config]]) 用法同post类似,用于修改数据 axios.put("/data.json", data).then(res=>{ console.log(res) }); let data = {uname:"dingding",upwd:123456}; // axios.patch(url[, data[, config]]) 用法同post类似,用于修改数据 axios.patch("/data.json", data).then(res=>{ console.log(res) });
delete方法
axios.delete(url[, config])与axios.get(url[, config])用法基本相似,但是作用不同,它用于删除数据,同get方法一样也可以有几种写法 。
delete请求有时候需要把参数拼接到URL上,有时候像post请求那样把参数放在请求体里面。至于具体怎么调用,需要和后端商量好!
- 方式一:get - params
// 使用别名法 // 传参的2种形式,同get 1、params axios .delete("/data.json", { params: { id: 12 } }) .then(res => { console.log(res, "delete"); }); 2、查询字符串形式,即参数拼接到url里 axios .delete("/data.json?id=2", { params: { id: 12 } }) .then(res => { console.log(res, "delete"); }); // 不使用别名法 —————通过向axios传递的相关配置创建请求__axios(config) let params = { id: 5 }; axios({ method:'delete', url:'/data.json', params:params }).then(res=>{ console.log(res) })
- 方式二:post - data
使用类似post请求方式,把axios.delete()中的params改为data,这样请求会把内容放入请求体里面
// 使用别名法 // data axios .delete("/data.json", { data: { id: 5 } }) .then(res => { console.log(res); }); // 不使用别名法 ————通过传递相关配置创建请求 let data = { id: 5 }; axios({ method:'delete', url:'/data.json', data:data }).then(res=>{ console.log(res) })
注意:delete请求中,get-params方式和post-data方式相关请求信息的区别
- params方式会将请求参数拼接在URL上面,Request URL: http://localhost:8080/data.json?id=5
- 参数形式:id:5
- Content-Type: text/html; charset=utf-8
- data方式不会讲参数拼接,是直接放置在请求体中的(因为向服务器提交了内容,所以,请求头里才会有请求数据的类型),Request URL: http://localhost:8080/data.json
- 参数形式:{id:5}
- Content-Type: application/json
总结:上述方法中均对应两种写法:(1)使用别名:形如axios.get();(2)不使用别名:形如axios();
并发请求
并发请求,就是同时进行多个请求,并统一处理返回值。
在例子中,我们使用axios.all(),对data.json/city.json同时进行请求,使用axios.spread(),对返回的结果分别进行处理。代码如下:
<template> <div class="hello">......</div> </template> <script> import axios from "axios"; export default { name: "HelloWorld", created() { // 并发请求 // 并发请求用到了axios的两个方法:axios.all('参数是一个数组')、axios.spread('回调函数') axios.all([axios.get("/data.json"), axios.get("/city.json")]).then( axios.spread((dataRes, cityRes) => { console.log(dataRes, cityRes); }) ); }, }; </script> <style scoped> </style>
注意:axios.all的参数是请求函数的数组,在对应的回调then中,调用axios.spead对返回值进行处理即可。
并发请求的应用场景:需要同时进行多个请求,并且需要同时处理接口调用的返回值的时候,我们可以使用并发请求。
◼️ Axios进阶用法(实例、配置、拦截器、取消请求等)
1、axios实例的创建与配置
比如:后端接口地址有多个(www.test.com、www.example.com),并且超时时长不同,比如1000ms、2000ms,这个时候,我们可以创建实例,利用axios实例进行网络请求。
思路如下:创建多个实例,配置不同的超时时长,用不同的实例去请求不同的接口。使用axios.acreate来创建实例,配置相关信息,进行网络请求。代码如下:
<template> <div class="hello">......</div> </template> <script> import axios from "axios"; // 场景:如果后端接口地址有多个,并且超时时长不一样,此时我们可以我们可以创建axios实例,利用axios实例进行网络请求 export default { name: "HelloWorld", created() { // 创建axios实例1 let instance = axios.create({ baseURL: "http://loacalhost:8080", timeout: 1000, }); instance.get("/data.json").then((res) => { console.log(res); }); // 创建axios实例2 ————倘若有两个域名或设置超时时长不一样,我们可以再创建一个axios实例 let instance2 = axios.create({ baseURL: "http://loacalhost:8081", timeout: 2000, }); instance2.get("/city.json").then((res) => { console.log(res); }); }, }; </script> <style scoped> </style>
备注:此时我们就可以访问http://loacalhost:8080与http://loacalhost:8081两个不同域名的接口,并且使用不同的配置。
👉 axios实例的相关配置
(1)配置列表:
- baseURL:请求的域名 / 基本地址。
- timeout:请求的超时时长,默认:1000毫秒(ms),超过这个时长后端会报(返回)401超时。
备注:一般由后端定义,后端的接口需要的处理时长较长的时候,如果请求的时间过长,后端处理不过来,就会阻塞,给服务器造成较大的压力。设置后,可以及时释放掉。
- url:请求的路径。
- method:请求的方法。如:get、post、put、patch、delete等。
- headers:请求头。
- params:将请求参数拼接到url上
- data:将请求参数放置到请求体里
let instance = axios.create({ // 创建实例时设置配置默 baseURL: "", //请求的域名/基本地址 timeout: 2000, //请求的超时时长,单位毫秒,默认。 url: "/data.json", //请求路径 method: "get", //请求方法 headers: { //设置请求头————我们可以给请求头添加一些参数 token: "", post: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' } }, params: { id: 5 }, //将请求参数拼接到url上 data: { id: 5 }, //将请求参数放置到请求体里 });
(2)三种配置方式:
- axios全局配置
axios.defaults.baseURL = 'http://localhost:8080' axios.defaults.timeout = 2000
备注:在一个项目当中,我们经常存在需要多次请求同一个基本URL下的不同路由,如果每次发送请求都书写一遍基本URL无疑会产生大量的代码重复,因此,可以使用全局配置来简化代码。 默认配置 | Axios 中文文档 | Axios 中文网
- axios实例配置
let instance = axios.create(); instance.defaults.timeout = 3000
- axios请求配置
instance.get('/data.json',{ timeout:5000 })
配置方式的优先级:axios全局配置 < axios实例配置 < axios请求配置
(3)常用参数配置的使用方法
- 示例1:
let instance1 = axios.create({ baseURL: "http://localhost:9090", timeout: 1000, }); instance1 .get("/contactList", { params: { id: 5, }, }) .then((res) => { console.log(res); });
分析:配置的参数为baseURL:‘http://localhost:8080’,timeout:1000,method:‘get’,params:{ id:10},url:’/contactList’
- 示例2:
let instance2 = axios.create({ baseURL: "http://localhost:8081", timeout: 3000, }); instance2 .get("/contactList", { timeout: 5000, }) .then((res) => { console.log(res); });
分析:配置的参数为baseURL:‘http://localhost:8081’,timeout:5000,method:‘get’,url:’/contactList’
注意:最终的有效配置是由优先级高的覆盖优先级低的。
2、拦截器
何为拦截器?就是在请求前或响应被处理前拦截他们,分为两种:请求拦截器与响应拦截器
(1)axios拦截器的使用方法
- 请求拦截器 ——在请求之前拦截请求
// 添加请求拦截器 /*需要拦截请求的原因 * 1.config中包含了某些不符合服务器要求的信息 * 2.发送网络请求的时候需要向用户展示一些加载中的图标 * 3.网站需要登录才能请求资源,也就是需要token才能请求资源*/ axios.interceptors.request.use(config => { // 在发送请求之前做些什么 console.log(config) return config; //拦截器里一定要记得将拦截的结果处理后返回,否则无法进行数据获取 }, err=>{ // 对请求错误做些什么 console.log(err) return Promise.reject(err) // 在请求错误的时候的逻辑处理 });
备注:可以为自定义 axios 实例添加拦截器 👇
var instance = axios.create([config]); instance.interceptors.request.use(function () {/*...*/});
- 响应拦截器 ——在被then,catch处理前拦截响应
// 添加响应拦截器 axios.interceptors.response.use(res => { // 在请求成功后的数据处理 console.log(res) return res.data; // 对响应数据做点什么 }, err=>{ // 对响应错误做些什么 console.log(err) return Promise.reject(err) // 在响应错误的时候的逻辑处理 });
- 取消拦截器(了解)
let inter = axios.interceptors.request.use(config=>{ config.header={ auth:true } return config }) axios.interceptors.request.eject(inter)
🌲 封装网络请求函数| 利用axios实例进行网络请求
基于以上知识点的梳理,我们就可以封装一个简单的request网络请求函数
在实际的项目中,我们不可能全程只发送一次网络请求,如果我们每进行一次网络请求就单独书写一个axios配置,将来如果axios不再进行维护或者项目需要更换其他的网络请求库的时候,需要重构的代码量无疑是巨大的。
因此,我们试想可不可以将网络请求单独抽离并封装为函数,进行网络请求的时候只需要调用对应的函数并且传入参数即可。这样将来即使需要更换请求库,也只需要对封装的函数进行修改而不是大量重构代码,可以大大减少工作量。
基于这样的需求,更推荐在项目中使用axios实例的方式进行网络请求。
export function request(config) { // 1. 创建axios实例 const instance = axios.create({ baseURL: "http://localhost:8080", timeout: 5000, }); // 2. axios拦截器的使用 // 2.1 添加请求拦截器 /** 需要拦截请求的原因 * 1.config中包含了某些不符合服务器要求的信息 * 2.发送网络请求的时候需要向用户展示一些加载中的图标 * 3.网站需要登录才能请求资源,也就是需要token才能请求资源 */ instance.interceptors.request.use( (config) => { // 在发送请求之前做些什么 return config; //拦截器里一定要记得将拦截的结果处理后返回,否则无法进行数据获取 }, (err) => { // 对请求错误做些什么 return Promise.reject(err); // 在请求错误的时候的逻辑处理 } ); // 2.2 添加响应拦截器 instance.interceptors.response.use( (res) => { // 在请求成功后对响应数据做处理 return res; // 对响应数据做点什么 }, (err) => { // 对响应错误做些什么 return Promise.reject(err); // 在响应错误的时候的逻辑处理 } ); // 3. 发送网络请求 //axios实例本身返回的就是Promise对象,直接调用即可 return instance(config); }
上述代码就是一个简单的request网络请求函数封装,这样每次调用其进行网络请求的时候创建的都是一个单独的axios实例,可以进行更加灵活的配置。
需要值得注意的地方就是拦截器,拦截器会对请求和响应的结果进行一定的处理,不过配置拦截器后一定要记得将拦截的结果在最后放行。
(2) 实用示例
◾ 实用举例A:登录权限
// 需要token的接口 let instance = axios.create({}); instance.interceptors.request.use(config=>{ config.headers.token = ''; //这种写法会覆盖掉headers中的其他参数,导致headers中只包含token这一个参数,所以不建议这种写法 // config.headers = { // token: '' // } return config }, err => { return Promise.reject(err); })
// 不需要token接口 let newInstance = axios.create({});
◾ 实用举例B:移动端开发数据加载loading动画
// 请求时加载loading动画 let instance_phone = axios.create({}); instance_phone.interceptors.request.use(config=>{ $('#loading').show(); return config }, err => { return Promise.reject(err); }) instance_phone.interceptors.response.use(res=>{ $('#loading').hide(); return res }, err => { return Promise.reject(err); })
备注:实现的效果是请求数据的时候显示loading动画,数据响应后隐藏loading动画。
结合请求拦截器与响应拦截器来说,不管是请求错误还是响应错误,都会执行catch方法。
// 请求拦截器 axios.interceptors.request.use( config => { // 在发送请求前做些什么 return config; }, err => { // 在请求错误的时候的逻辑处理 return Promise.reject(err); } ); // 响应拦截器 axios.interceptors.response.use( res => { // 在请求成功后的数据处理 return res; }, err => { // 在响应错误的时候的逻辑处理 return Promise.reject(err); } ); axios .get("/data.json") .then(res => { console.log(res); }) .catch(err => { console.log(res); });
在实际开发中,不会再每次网络请求的时候,都使用catch方法,可以添加统一的错误处理方法。代码如下:
// 请求错误处理 let instance = axios.create({}); instance.interceptors.request.use( config => { return config; }, err => { // 请求错误的常见状态码:4XX 401-请求超时 404-mot found $("#error").show(); setTimeout(()=>{ $("#error").hide(); }, 2000) return Promise.reject(err); } ); // 响应错误处理 instance.interceptors.response.use( res => { return res; }, err => { // 响应错误的常见状态码 5XX 500-服务器错误 502-服务器重启 $("#error").show(); setTimeout(()=>{ $("#error").hide(); }, 2000) return Promise.reject(err); } ); instance.get("/data.json").then(res=>{ console.log(res,'请求成功') }).catch(err=>{ console.log(err,'除了拦截器设置的处理之外的其他处理') })
思路分析:首先创建实例,给实例设置请求拦截器与响应拦截器。
(1)请求错误的常见状态码以4开头,如401-请求超时、404-接口未找到;
(2)响应错误的常见状态码以5开头,如500-服务器错误、502-服务器重启等。
(3)处理设置请求拦截器与响应拦截器的操作外,如果还要其他操作,我们可以在请求的时候,再使用catch方法。
3、取消请求(不常用,了解)
取消请求:用于取消正在进行的http请求(不常用,作为了解)
- 代码示例
<template> <div class="hello">取消请求</div> </template> <script> import axios from "axios"; export default { name: "HelloWorld", created() { // 取消请求:用于取消正在进行的http请求(不常用,作为了解) let source = axios.CancelToken.source(); axios .get("/data.json", { cancelToken: source.token, }) .then((res) => { console.log(res); }) .catch((err) => { console.log(err); }); // 取消请求(其中,参数message是可选) source.cancel("自定义的字符串可选"); }, }; </script> <style scoped> </style>
- 应用场景
在查询数据的时候,很长时间(3-5s)仍未获取数据,这个时候需要取消请求。
◼️ Axios进一步封装,在项目中的实际应用
在vue项目中,和后台交互获取数据这块,我们通常使用的是axios库,它是基于promise的http库,可运行在浏览器端和node.js中。axios有很多优秀的特性,例如拦截请求和响应、取消请求、转换json、客户端防御XSRF等。
在一个完整的项目中,和服务端的交互会很频繁,一个项目会有很多请求,冗余代码很多。所以将请求封装,统一管理还是很有必要的。
本文介绍的axios的封装主要目的就是在帮助我们简化项目代码和利于后期的更新维护。提高代码的可读性和可维护性,减少、简化代码的书写,这也是封装的意义所在
代理
// Vue-CLI2旧版本代理 // Vue-CLI2需在 config/index.js 里配置 dev: { // Paths assetsSubDirectory: 'static', assetsPublicPath: '/', // 后端请求地址代理,配置后testIp再之后的页面调用时就直接指代 http://197.82.15.15:8088 proxyTable: { '/testIp': { target: 'http://197.82.15.15:8088', changeOrigin: true, pathRewrite: { '^/testIp': '' } }, '/elseIp': { target: 'http://182.83.19.15:8080', changeOrigin: true, pathRewrite: { '^/esleIp': '' } }, }, // Vue-CLI3新版本代理 // vue cil3需在 vue.config.js 文件里配置 devServer: { overlay: { // 让浏览器 overlay 同时显示警告和错误 warnings: true, errors: true }, host: "localhost", port: 8080, // 端口号 https: false, // https:{type:Boolean} open: false, // 配置后自动启动浏览器 hotOnly: true, // 热更新 // proxy: 'http://localhost:8080' // 配置跨域处理,只有一个代理 proxy: { //配置多个代理 "/testIp": { target: "http://197.0.0.1:8088", changeOrigin: true, ws: true,//websocket支持 secure: false, pathRewrite: { "^/testIp": "/" } }, "/elseIp": { target: "http://197.0.0.2:8088", changeOrigin: true, //ws: true,//websocket支持 secure: false, pathRewrite: { "^/elseIp": "/" } }, } }
当项目有多个后台的时候,可以在api文件夹下 新建一个elseApi.js ,书写当前ip下的接口请求。方法同上,只是 let resquest = "/elseIp"
封装
* request.js
在项目src目录下新建utils文件夹,然后在其中新建 request.js文件,这个文件是主要书写axios的封装过程。
/**** request.js ****/ // 导入axios import axios from "axios"; // 使用element-ui Message做消息提醒 import { Message } from "element-ui"; // 1. 创建新的axios实例, const service = axios.create({ // 公共接口--webpack中的全局变量process.env.BASE_API // 为了适应多个后台或者开发的时候的api地址和发布的时候的api地址不一样这种情况 baseURL: process.env.BASE_API, // 超时时间 单位是ms,这里设置了3s的超时时间 timeout: 3 * 1000, }); // 2. 请求拦截器 service.interceptors.request.use( (config) => { // 发请求前做的一些处理,数据转化,配置请求头,设置token,设置loading等,根据需求去添加 config.data = JSON.stringify(config.data); // 数据转化,也可以使用qs转换 config.headers = { "Content-Type": "application/x-www-form-urlencoded", // 配置请求头 }; //注意使用token的时候需要引入cookie方法或者用本地localStorage等方法,推荐js-cookie const token = getCookie("名称"); // 这里取token之前,你肯定需要先拿到token,存一下 if (token) { config.params = { token: token }; // 如果要求携带在参数中 config.headers.token = token; // 如果要求携带在请求头中 } return config; }, (error) => { Promise.reject(error); } ); // 3. 响应拦截器 service.interceptors.response.use( (response) => { //接收到响应数据并成功后的一些共有的处理,关闭loading等 return response; }, (error) => { /* **** 接收到异常响应的处理开始 **** */ if (error && error.response) { // 1. 公共错误处理 // 2. 根据响应码具体处理 switch (error.response.status) { case 400: error.message = "错误请求"; break; case 401: error.message = "未授权,请重新登录"; break; case 403: error.message = "拒绝访问"; break; case 404: error.message = "请求错误,未找到该资源"; window.location.href = "/NotFound"; break; case 405: error.message = "请求方法未允许"; break; case 408: error.message = "请求超时"; break; case 500: error.message = "服务器端出错"; break; case 501: error.message = "网络未实现"; break; case 502: error.message = "网络错误"; break; case 503: error.message = "服务不可用"; break; case 504: error.message = "网络超时"; break; case 505: error.message = "http版本不支持该请求"; break; default: error.message = `连接错误${error.response.status}`; } } else { // 超时处理 if (JSON.stringify(error).includes("timeout")) { Message.error("服务器响应超时,请刷新当前页"); } error.message("连接服务器失败"); } Message.error(error.message); /* **** 处理结束 **** */ // 如果不需要错误处理,以上的处理过程都可省略 return Promise.resolve(error.response); } ); // 4. 导入文件 export default service;
关于数据转换的说明
上述的代码都是请求的配置项,非必须,也是分情况的,data/headers/params 这种本身的参数都有多种,和后台沟通,需要什么就配什么!
👉 config.data = JSON.stringify(config.data)使用JSON.stringify()还是qs.stringify()方法取决于你的后台想要的是json类型的传参还是需要传递字符串类型的参数。JSON.stringify() 方法将 JavaScript 对象转换为json类型的字符串。
qs.stringify()将对象序列化成URL的形式,以&进行拼接,也就是说qs转换会转换成为键值对拼接的字符串形式。
👉 const token = getCookie('名称')这是token的取值,在取之前你肯定需要发请求拿到token,然后setCookie存起来,而名称就是你存的token的名称,每个人的不一样。
👉 config.headers = { 'Content-Type':'application/x-www-form-urlencoded' }请求头内容的配置,也是不同的,application/x-www-form-urlencoded :form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式),你可以根据实际情况去配置自己需要的;
写代码的过程是自己动脑去搭建工程的过程,希望给到大家一些启发:善于搜索,善于思考,善于总结;
另外,文章的知识点是你建立在,你对vue有一定基础上的,如果你没有相关的基础作为根基,还是建议大家去学习掌握基础知识后进行参考。
* Axios中的http.js
在项目src目录下的utils文件夹中新建 http.js文件,这个文件是主要书写几种请求方式的封装过程。
/**** http.js ****/ // 导入封装好的axios实例 import request from './request' const http ={ /** * methods: 请求 * @param url 请求地址 * @param params 请求参数 */ // 对象方法的简写get:function()(url,params){ ... } get(url,params){ const config = { method: 'get', url:url } if(params) config.params = params return request(config) }, post(url,params){ const config = { method: 'post', url:url } if(params) config.data = params return request(config) }, put(url,params){ const config = { method: 'put', url:url } if(params) config.params = params return request(config) }, delete(url,params){ const config = { method: 'delete', url:url } if(params) config.params = params return request(config) } } //导出 export default http
在项目src目录下新建api文件夹,然后在其中新建 api.js文件,这个文件是主要书写API的封装过程。当一个项目中后台请求不是同一个IP地址,是多个IP地址的时候,可以在api文件夹下创建多个js文件,用来调用请求
// api.js有两种导出方式,分类导出和全部导出 // 分类导出 import http from '../utils/http' /** * @params resquest 请求地址 例如:http://197.82.15.15:8088/request/... * @param '/testIp'代表vue-cil中config,index.js中配置的代理 */ let resquest = "/testIp/request/" // get请求 export function getListAPI(params){ return http.get(`${resquest}/getList.json`,params) } // post请求 export function postFormAPI(params){ return http.post(`${resquest}/postForm.json`,params) } // put 请求 export function putSomeAPI(params){ return http.put(`${resquest}/putForm.json`,params) } // delete 请求 export function deleteListAPI(params){ return http.delete(`${resquest}/deleteList.json`,params) } // 全部导出 import http from '../utils/http' /** * @params resquest 请求地址 例如:http://197.82.15.15:8088/request/... * @param '/testIp'代表vue-cil中config,index.js中配置的代理 */ let resquest = "/testIp/request/" // get请求 export default{ getListAPI(params){ return http.get(`${resquest}/getList.json`,params) }, postFormAPI(params){ return http.post(`${resquest}/postForm.json`,params) }, putFormAPI(params){ return http.put(`${resquest}/putForm.json`,params) }, deleteListAPI(params){ return http.delete(`${resquest}/deleteList.json`,params) } }
以上封装完之后,接下来就是如何调用
调用
在Vue中调用接口
// 把api分类导入,用到哪个api 就调用哪个接口 ————适用于上面接口的分类导出 import {getListAPI,postFormAPI, putSomeAPI, deleteListAPI} from '@/api/api' methods: { // promise调用,链式调用, getList()括号内只接受参数; // get不传参 getList() { getListAPI().then(res => console.log(res)).catch(err => console.log(err)) }, // post传参 postForm(formData) { let data = formData postFormAPI(data).then(res => console.log(res)).catch(err => console.log(err)) }, // async await同步调用 async postForm(formData) { const postRes = await postFormAPI(formData) const putRes = await putSomeAPI({data: 'putTest'}) const deleteRes = await deleteListAPI(formData.name) // 数据处理 console.log(postRes); console.log(putRes); console.log(deleteRes); }, } // 把api全部导入,然后用到哪个api调用哪个api ————适用于全部导出 import api from '@/api/api' methods: { getList() { api.getListAPI(data).then(res => { // 数据处理 }).catch(err => console.log(err)) } }