我是南城余!阿里云开发者平台专家博士证书获得者!
欢迎关注我的博客!一同成长!
一名从事运维开发的worker,记录分享学习。
专注于AI,运维开发,windows Linux 系统领域的分享!
本章节对应知识库
南城余的知识库
九、Vue3数据交互axios
9.0 预讲知识-promise
9.0.1 普通函数和回调函数
普通函数: 正常调用的函数,一般函数执行完毕后才会继续执行下一行代码
<script>let fun1 = () =>{console.log("fun1 invoked")}// 调用函数fun1()// 函数执行完毕,继续执行后续代码console.log("other code processon")
</script>
回调函数: 一些特殊的函数,表示未来才会执行的一些功能,后续代码不会等待该函数执行完毕就开始执行了
<script>// 设置一个2000毫秒后会执行一次的定时任务setTimeout(function (){console.log("setTimeout invoked")},2000)console.log("other code processon")
</script>
9.0.2 Promise 简介
前端中的异步编程技术,类似Java中的多线程+线程结果回调!
-
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了
Promise
对象。 -
所谓
Promise
,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise
对象有以下两个特点。
(1)Promise对象代表一个异步操作,有三种状态:`Pending`(进行中)、`Resolved`(已完成,又称 Fulfilled)和`Rejected`(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是`Promise`这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从`Pending`变为`Resolved`和从`Pending`变为`Rejected`。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。
9.0.3 Promise 基本用法
ES6规定,Promise对象是一个构造函数,用来生成Promise实例。
<script>/* 1.实例化promise对象,并且执行(类似Java创建线程对象,并且start)参数: resolve,reject随意命名,但是一般这么叫!参数: resolve,reject分别处理成功和失败的两个函数! 成功resolve(结果) 失败reject(结果)参数: 在function中调用这里两个方法,那么promise会处于两个不同的状态状态: promise有三个状态pending 正在运行resolved 内部调用了resolve方法rejected 内部调用了reject方法参数: 在第二步回调函数中就可以获取对应的结果 */let promise =new Promise(function(resolve,reject){console.log("promise do some code ... ...")//resolve("promise success")reject("promise fail")})console.log('other code1111 invoked')//2.获取回调函数结果 then在这里会等待promise中的运行结果,但是不会阻塞代码继续运行promise.then(function(value){console.log(`promise中执行了resolve:${value}`)},function(error){console.log(`promise中执行了reject:${error}`)})// 3 其他代码执行 console.log('other code2222 invoked')</script>
9.0.4 Promise catch()
Promise.prototype.catch
方法是.then(null, rejection)
的别名,用于指定发生错误时的回调函数。
<script>let promise =new Promise(function(resolve,reject){console.log("promise do some code ... ...")// 故意响应一个异常对象throw new Error("error message")})console.log('other code1111 invoked')/* then中的reject()的对应方法可以在产生异常时执行,接收到的就是异常中的提示信息then中可以只留一个resolve()的对应方法,reject()方法可以用后续的catch替换then中的reject对应的回调函数被后续的catch替换后,catch中接收的数据是一个异常对象*/promise.then(function(resolveValue){console.log(`promise中执行了resolve:${resolveValue}`)}//,//function(rejectValue){console.log(`promise中执行了reject:${rejectValue}`)}).catch(function(error){console.log(error)} )console.log('other code2222 invoked')
</script>
9.0.5 async和await的使用
async和await是ES6中用于处理异步操作的新特性。通常,异步操作会涉及到Promise对象,而async/await则是在Promise基础上提供了更加直观和易于使用的语法。
async 用于标识函数的
-
async标识函数后,async函数的返回值会变成一个promise对象
-
如果函数内部返回的数据是一个非promise对象,async函数的结果会返回一个成功状态 promise对象
-
如果函数内部返回的是一个promise对象,则async函数返回的状态与结果由该对象决定
-
如果函数内部抛出的是一个异常,则async函数返回的是一个失败的promise对象
<script>/* async 用于标识函数的1. async标识函数后,async函数的返回值会变成一个promise对象2. 如果函数内部返回的数据是一个非promise对象,async函数的结果会返回一个成功状态 promise对象3. 如果函数内部返回的是一个promise对象,则async函数返回的状态与结果由该对象决定4. 如果函数内部抛出的是一个异常,则async函数返回的是一个失败的promise对象*/async function fun1(){//return 10//throw new Error("something wrong")let promise = Promise.reject("heihei")return promise}let promise =fun1()promise.then(function(value){console.log("success:"+value)}).catch(function(value){console.log("fail:"+value)})
</script>
await
- await右侧的表达式一般为一个promise对象,但是也可以是一个其他值
- 如果表达式是promise对象,await返回的是promise成功的值
- await会等右边的promise对象执行结束,然后再获取结果,后续代码也会等待await的执行
- 如果表达式是其他值,则直接返回该值
- await必须在async函数中,但是async函数中可以没有await
- 如果await右边的promise失败了,就会抛出异常,需要通过 try … catch捕获处理
<script>/* 1. await右侧的表达式一般为一个promise对象,但是也可以是一个其他值2. 如果表达式是promise对象,await返回的是promise成功的值3. await会等右边的promise对象执行结束,然后再获取结果,后续代码也会等待await的执行4. 如果表达式是其他值,则直接返回该值5. await必须在async函数中,但是async函数中可以没有await6. 如果await右边的promise失败了,就会抛出异常,可以通过 try ... catch捕获处理*/async function fun1(){return 10}async function fun2(){try{let res = await fun1()//let res = await Promise.reject("something wrong")}catch(e){console.log("catch got:"+e) }console.log("await got:"+res)}fun2()
</script>
9.1 Axios介绍
ajax
-
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
-
AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
-
AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
-
AJAX 不需要任何浏览器插件,但需要用户允许 JavaScript 在浏览器上执行。
-
XMLHttpRequest 只是实现 Ajax 的一种方式。
ajax工作原理:
原生javascript方式进行ajax(了解):
<script>function loadXMLDoc(){var xmlhttp;if (window.XMLHttpRequest){// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码xmlhttp=new XMLHttpRequest();}else{// IE6, IE5 浏览器执行代码xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}// 设置回调函数处理响应结果xmlhttp.onreadystatechange=function(){if (xmlhttp.readyState==4 && xmlhttp.status==200){document.getElementById("myDiv").innerHTML=xmlhttp.responseText;}}// 设置请求方式和请求的资源路径xmlhttp.open("GET","/try/ajax/ajax_info.txt",true);// 发送请求xmlhttp.send();}
</script>
什么是axios 官网介绍:https://axios-http.com/zh/docs/intro
- Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js
http
模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。它有如下特性- 从浏览器创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换JSON数据
- 客户端支持防御XSRF
9.2 Axios 入门案例
1 案例需求:请求后台获取随机土味情话
- 请求的url
https://api.uomg.com/api/rand.qinghua?format=json 或者使用 http://forum.atguigu.cn/api/rand.qinghua?format=json
- 请求的方式
GET/POST
- 数据返回的格式
{"code":1,"content":"我努力不是为了你而是因为你。"}
2 准备项目
npm create vite
npm install
/*npm install vue-router@4 --save
npm install pinia */
3 安装axios
npm install axios
4 设计页面(App.Vue)
<script setup type="module">import axios from 'axios'import { onMounted,reactive } from 'vue';let jsonData =reactive({code:1,content:'我努力不是为了你而是因为你'})let getLoveMessage =()=>{axios({method:"post", // 请求方式url:"https://api.uomg.com/api/rand.qinghua?format=json", // 请求的urldata:{ // 当请求方式为post时,data下的数据以JSON串放入请求体,否则以key=value形式放url后username:"123456"}}).then( function (response){//响应成功时要执行的函数console.log(response)Object.assign(jsonData,response.data)}).catch(function (error){// 响应失败时要执行的函数console.log(error)})}/* 通过onMounted生命周期,自动加载一次 */onMounted(()=>{getLoveMessage()})
</script><template><div><h1>今日土味情话:{{jsonData.content}}</h1><button @click="getLoveMessage">获取今日土味情话</button></div>
</template><style scoped>
</style>
5 启动测试
npm run dev
异步响应的数据结构
- 响应的数据是经过包装返回的!一个请求的响应包含以下信息。
{// `data` 由服务器提供的响应data: {},// `status` 来自服务器响应的 HTTP 状态码status: 200,// `statusText` 来自服务器响应的 HTTP 状态信息statusText: 'OK',// `headers` 是服务器响应头// 所有的 header 名称都是小写,而且可以使用方括号语法访问// 例如: `response.headers['content-type']`headers: {},// `config` 是 `axios` 请求的配置信息config: {},// `request` 是生成此响应的请求// 在node.js中它是最后一个ClientRequest实例 (in redirects),// 在浏览器中则是 XMLHttpRequest 实例request: {}
}
- then取值
then(function (response) {console.log(response.data);console.log(response.status);console.log(response.statusText);console.log(response.headers);console.log(response.config);
});
6 通过async和await处理异步请求
<script setup type="module">import axios from 'axios'import { onMounted,reactive } from 'vue';let jsonData =reactive({code:1,content:'我努力不是为了你而是因为你'})let getLoveWords = async ()=>{return await axios({method:"post",url:"https://api.uomg.com/api/rand.qinghua?format=json",data:{username:"123456"}})}let getLoveMessage =()=>{let {data} = await getLoveWords()Object.assign(message,data)}/* 通过onMounted生命周期,自动加载一次 */onMounted(()=>{getLoveMessage()})
</script><template><div><h1>今日土味情话:{{jsonData.content}}</h1><button @click="getLoveMessage">获取今日土味情话</button></div>
</template><style scoped>
</style>
axios在发送异步请求时的可选配置:
{// `url` 是用于请求的服务器 URLurl: '/user',// `method` 是创建请求时使用的方法method: 'get', // 默认值// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URLbaseURL: 'https://some-domain.com/api/',// `transformRequest` 允许在向服务器发送前,修改请求数据// 它只能用于 'PUT', 'POST' 和 'PATCH' 这几个请求方法// 数组中最后一个函数必须返回一个字符串, 一个Buffer实例,ArrayBuffer,FormData,或 Stream// 你可以修改请求头。transformRequest: [function (data, headers) {// 对发送的 data 进行任意转换处理return data;}],// `transformResponse` 在传递给 then/catch 前,允许修改响应数据transformResponse: [function (data) {// 对接收的 data 进行任意转换处理return data;}],// 自定义请求头headers: {'X-Requested-With': 'XMLHttpRequest'},// `params` 是与请求一起发送的 URL 参数// 必须是一个简单对象或 URLSearchParams 对象params: {ID: 12345},// `paramsSerializer`是可选方法,主要用于序列化`params`// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)paramsSerializer: function (params) {return Qs.stringify(params, {arrayFormat: 'brackets'})},// `data` 是作为请求体被发送的数据// 仅适用 'PUT', 'POST', 'DELETE 和 'PATCH' 请求方法// 在没有设置 `transformRequest` 时,则必须是以下类型之一:// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams// - 浏览器专属: FormData, File, Blob// - Node 专属: Stream, Bufferdata: {firstName: 'Fred'},// 发送请求体数据的可选语法// 请求方式 post// 只有 value 会被发送,key 则不会data: 'Country=Brasil&City=Belo Horizonte',// `timeout` 指定请求超时的毫秒数。// 如果请求时间超过 `timeout` 的值,则请求会被中断timeout: 1000, // 默认值是 `0` (永不超时)// `withCredentials` 表示跨域请求时是否需要使用凭证withCredentials: false, // default// `adapter` 允许自定义处理请求,这使测试更加容易。// 返回一个 promise 并提供一个有效的响应 (参见 lib/adapters/README.md)。adapter: function (config) {/* ... */},// `auth` HTTP Basic Authauth: {username: 'janedoe',password: 's00pers3cret'},// `responseType` 表示浏览器将要响应的数据类型// 选项包括: 'arraybuffer', 'document', 'json', 'text', 'stream'// 浏览器专属:'blob'responseType: 'json', // 默认值// `responseEncoding` 表示用于解码响应的编码 (Node.js 专属)// 注意:忽略 `responseType` 的值为 'stream',或者是客户端请求// Note: Ignored for `responseType` of 'stream' or client-side requestsresponseEncoding: 'utf8', // 默认值// `xsrfCookieName` 是 xsrf token 的值,被用作 cookie 的名称xsrfCookieName: 'XSRF-TOKEN', // 默认值// `xsrfHeaderName` 是带有 xsrf token 值的http 请求头名称xsrfHeaderName: 'X-XSRF-TOKEN', // 默认值// `onUploadProgress` 允许为上传处理进度事件// 浏览器专属onUploadProgress: function (progressEvent) {// 处理原生进度事件},// `onDownloadProgress` 允许为下载处理进度事件// 浏览器专属onDownloadProgress: function (progressEvent) {// 处理原生进度事件},// `maxContentLength` 定义了node.js中允许的HTTP响应内容的最大字节数maxContentLength: 2000,// `maxBodyLength`(仅Node)定义允许的http请求内容的最大字节数maxBodyLength: 2000,// `validateStatus` 定义了对于给定的 HTTP状态码是 resolve 还是 reject promise。// 如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),// 则promise 将会 resolved,否则是 rejected。validateStatus: function (status) {return status >= 200 && status < 300; // 默认值},// `maxRedirects` 定义了在node.js中要遵循的最大重定向数。// 如果设置为0,则不会进行重定向maxRedirects: 5, // 默认值// `socketPath` 定义了在node.js中使用的UNIX套接字。// e.g. '/var/run/docker.sock' 发送请求到 docker 守护进程。// 只能指定 `socketPath` 或 `proxy` 。// 若都指定,这使用 `socketPath` 。socketPath: null, // default// `httpAgent` and `httpsAgent` define a custom agent to be used when performing http// and https requests, respectively, in node.js. This allows options to be added like// `keepAlive` that are not enabled by default.httpAgent: new http.Agent({ keepAlive: true }),httpsAgent: new https.Agent({ keepAlive: true }),// `proxy` 定义了代理服务器的主机名,端口和协议。// 您可以使用常规的`http_proxy` 和 `https_proxy` 环境变量。// 使用 `false` 可以禁用代理功能,同时环境变量也会被忽略。// `auth`表示应使用HTTP Basic auth连接到代理,并且提供凭据。// 这将设置一个 `Proxy-Authorization` 请求头,它会覆盖 `headers` 中已存在的自定义 `Proxy-Authorization` 请求头。// 如果代理服务器使用 HTTPS,则必须设置 protocol 为`https`proxy: {protocol: 'https',host: '127.0.0.1',port: 9000,auth: {username: 'mikeymike',password: 'rapunz3l'}},// see https://axios-http.com/zh/docs/cancellationcancelToken: new CancelToken(function (cancel) {}),// `decompress` indicates whether or not the response body should be decompressed // automatically. If set to `true` will also remove the 'content-encoding' header // from the responses objects of all decompressed responses// - Node only (XHR cannot turn off decompression)decompress: true // 默认值
}
9.3 Axios get和post方法
配置添加语法
axios.get(url[, config])axios.get(url,{上面指定配置key:配置值,上面指定配置key:配置值
})axios.post(url[, data[, config]])axios.post(url,{key:value //此位置数据,没有空对象即可{}},{上面指定配置key:配置值,上面指定配置key:配置值
})
测试get参数
<script setup type="module">import axios from 'axios'import { onMounted,ref,reactive,toRaw } from 'vue';let jsonData =reactive({code:1,content:'我努力不是为了你而是因为你'})let getLoveWords= async ()=>{try{return await axios.get('https://api.uomg.com/api/rand.qinghua',{params:{// 向url后添加的键值对参数format:'json',username:'zhangsan',password:'123456'},headers:{// 设置请求头'Accept' : 'application/json, text/plain, text/html,*/*'}})}catch (e){return await e}}let getLoveMessage =()=>{let {data} = await getLoveWords()Object.assign(message,data)}/* 通过onMounted生命周期,自动加载一次 */onMounted(()=>{getLoveMessage()})
</script><template><div><h1>今日土味情话:{{jsonData.content}}</h1><button @click="getLoveMessage">获取今日土味情话</button></div>
</template><style scoped>
</style>
测试post参数
<script setup type="module">import axios from 'axios'import { onMounted,ref,reactive,toRaw } from 'vue';let jsonData =reactive({code:1,content:'我努力不是为了你而是因为你'})let getLoveWords= async ()=>{try{return await axios.post('https://api.uomg.com/api/rand.qinghua',{//请求体中的JSON数据username:'zhangsan',password:'123456'},{// 其他参数params:{// url上拼接的键值对参数format:'json',},headers:{// 请求头'Accept' : 'application/json, text/plain, text/html,*/*','X-Requested-With': 'XMLHttpRequest'}})}catch (e){return await e}}let getLoveMessage =()=>{let {data} = await getLoveWords()Object.assign(message,data)}/* 通过onMounted生命周期,自动加载一次 */onMounted(()=>{getLoveMessage()})
</script><template><div><h1>今日土味情话:{{jsonData.content}}</h1><button @click="getLoveMessage">获取今日土味情话</button></div>
</template><style scoped>
</style>
9.4 Axios 拦截器
如果想在axios发送请求之前,或者是数据响应回来在执行then方法之前做一些额外的工作,可以通过拦截器完成
// 添加请求拦截器 请求发送之前
axios.interceptors.request.use(function (config) {// 在发送请求之前做些什么return config;}, function (error) {// 对请求错误做些什么return Promise.reject(error);}
);// 添加响应拦截器 数据响应回来
axios.interceptors.response.use(function (response) {// 2xx 范围内的状态码都会触发该函数。// 对响应数据做点什么return response;}, function (error) {// 超出 2xx 范围的状态码都会触发该函数。// 对响应错误做点什么return Promise.reject(error);}
);
- 定义src/axios.js提取拦截器和配置语法
import axios from 'axios'// 创建instance实例
const instance = axios.create({baseURL:'https://api.uomg.com',timeout:10000
})// 添加请求拦截
instance.interceptors.request.use(// 设置请求头配置信息config=>{//处理指定的请求头console.log("before request")config.headers.Accept = 'application/json, text/plain, text/html,*/*'return config},// 设置请求错误处理函数error=>{console.log("request error")return Promise.reject(error)}
)
// 添加响应拦截器
instance.interceptors.response.use(// 设置响应正确时的处理函数response=>{console.log("after success response")console.log(response)return response},// 设置响应异常时的处理函数error=>{console.log("after fail response")console.log(error)return Promise.reject(error)}
)
// 默认导出
export default instance
- App.vue
<script setup type="module">// 导入我们自己定义的axios.js文件,而不是导入axios依赖 import axios from './axios.js'import { onMounted,ref,reactive,toRaw } from 'vue';let jsonData =reactive({code:1,content:'我努力不是为了你而是因为你'})let getLoveWords= async ()=>{try{return await axios.post('api/rand.qinghua',{username:'zhangsan',password:'123456'},//请求体中的JSON数据{params:{format:'json',}}// 其他键值对参数)}catch (e){return await e}}let getLoveMessage =()=>{// 这里返回的是一个fullfilled状态的promisegetLoveWords().then((response) =>{console.log("after getloveWords")console.log(response)Object.assign(jsonData,response.data)})}/* 通过onMounted生命周期,自动加载一次 */onMounted(()=>{getLoveMessage()})
</script><template><div><h1>今日土味情话:{{jsonData.content}}</h1><button @click="getLoveMessage">获取今日土味情话</button></div></template><style scoped>
</style>