前后端交互

1-前后端交互概述

1.1接口调用方式

  • 原生ajax

  • 基于jQuery的ajax

  • fetch(ajax的升级版)

  • axios (第三方的库)

1.2 url 地址格式有哪些

  • 传统的url

    • http://host:port/path?query#fragment

    • http协议----https,ftp

    • host----域名或者IP地址

    • port----端口,http默认是80,可以省略

    • path----路径/比如/abc/a/b/c---虚拟的路径(并不是服务器中一定有个真实的目录,作用就是区分不同的资源)

    • query---查询参数,例如?name=zhangsan&age=14

    • Fragment:锚点(哈希hash),表示定位到页面的某个位置

  • Restful形式的url

  • 关于在请求头中指定 Content-Type 属性的的说明:

  • Content-Type: application/x-www-form-urlencoded;charset=utf-8
    ---传统表单形式
    比如:name=zhangsan&age=20&sex=男
    Content-Type:application/json		
    ----json形式
    比如:{name: 'zhangsan', age: '20', sex: '男'}
    注意:get请求是不能提交json对象数据格式的,传统网站的表单提交也是不支持json对象数据格式的。
  • 传统url地址通过?传参,Restful风格url地址通过/传参

2-异步编程问题与Promise概述

2.1 异步

Promise实例生成以后,可以用then方法指定resolved状态和reject状态的回调函数

2.3-Promise基本用法

一个 Promise 对象代表一个在这个 promise 被创建出来时不一定已知的值。它让你能够把异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来。 这样使得异步方法可以像同步方法那样返回值:异步方法并不会立即返回最终的值,而是会返回一个 promise,以便在未来某个时候把值交给使用者。

2.4 如何定义一个promise实例

我们使用new来构建一个Promise ,Promise的构造函数接收一个参数,是函数,并且传入两个参数: resolve,reject, 分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数

  • JavaScript的执行环境是「单线程」

  • 所谓单线程,是指JS引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完后才能执行下一个,它会「阻塞」其他任务。这个任务可称为主线程

  • 异步模式可以一起执行多个任务

  • JS中常见的异步调用

    • 定时任务

    • ajax

    • 事件函数

  • 案例演示:异步编程----对应服务器01.api

  • <script type="text/javascript">
        /*
          前后端交互-异步编程与Promise概述
        */
        var ret = null
        $.ajax({
          url: 'http://localhost:3004/data',
          success: function (data) {
            ret = data;
    
          }
        });
        console.log(ret)
    
        // ----------------------------
        // $.ajax({
        //   url: 'http://localhost:3004/data',
        //   success: function (data) {
        //     console.log(data)
        //   }
        // });
        // $.ajax({
        //   url: 'http://localhost:3004/data1',
        //   success: function (data) {
        //     console.log(data)
        //   }
        // });
        // $.ajax({
        //   url: 'http://localhost:3004/data2',
        //   success: function (data) {
        //     console.log(data)
        //   }
        // });
    
        // -----------------------------------
      </script>

    2.2 promise

  • 主要解决异步深层嵌套的问题(回调地狱)

  • promise 提供了简洁的API 使得异步操作更加容易--注意:promise可以让我们的写法看起来更清晰。

2.3-Promise基本用法

一个 Promise 对象代表一个在这个 promise 被创建出来时不一定已知的值。它让你能够把异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来。 这样使得异步方法可以像同步方法那样返回值:异步方法并不会立即返回最终的值,而是会返回一个 promise,以便在未来某个时候把值交给使用者。

2.4 如何定义一个promise实例

我们使用new来构建一个Promise ,Promise的构造函数接收一个参数,是函数,并且传入两个参数: resolve,reject, 分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数

Promise实例生成以后,可以用then方法指定resolved状态和reject状态的回调函数

//02.promise基本使用---
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  
  <script type="text/javascript">
    /*
      Promise基本使用
        1. Promise基本使用
          
    */
    // console.log(typeof Promise)
    // console.dir(Promise);

    //  我们使用new来构建一个Promise  Promise的构造函数接收一个参数,是函数,并且传入两个参						数:resolve,reject, 分别表示异步操作执行成功后的回调函数和异步操作执行失败后的								回调函数,并通过p.then()
     var p = new Promise(function(resolve, reject){
      // 这里用于实现异步任务
      setTimeout(function(){
        var flag = true;
        if(flag) {
          // 正常情况
          resolve('hello');
        }else{
          // 异常情况
          reject('出错了');
        }
      }, 100);
    });
    p.then(function(data){
      console.log(data) //对应正常的情况
    },function(data){
      console.log(data+"error")//对应异常的情况
    });
  </script>
</body>
</html>

待定状态(pending)的 Promise 对象要么会通过一个值被兑现(fulfilled),要么会通过一个原因(错误)被拒绝(rejected)。当这些情况之一发生时,我们用 promise 的 then 方法排列起来的相关处理程序就会被调用。如果 promise 在一个相应的处理程序被绑定时就已经被兑现或被拒绝了,那么这个处理程序就会被调用,因此在完成异步操作和绑定处理方法之间不会存在竞争状态。

  • 一个 Promise 必然处于以下几种状态之一:

    • 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。

    • 已兑现(fulfilled): 意味着操作成功完成。resolve()修改

    • 已拒绝(rejected): 意味着操作失败。 reject()修改

2.5 基于Promise发送Ajax请求,并解决地狱回调问题

  • 提前封装好的一段数据请求的代码:

  • var xhr = new XMLHttpRequest();
            xhr.open('get', url);
            xhr.send(null);
            xhr.onreadystatechange = function () {
              if (xhr.readyState != 4) return;
              if (xhr.readyState == 4 && xhr.status == 200) {
                // 正常接收---处理正常的情况
                
              } else {
                // 处理异常情况
               
              }
            };
  • 完整代码

  • <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
    </head>
    
    <body>
      <script type="text/javascript">
        /*
          基于Promise发送Ajax请求
        */
        function queryData(url) {
          var p = new Promise(function (resolve, reject) {
            var xhr = new XMLHttpRequest();
            xhr.open('get', url);
            xhr.send(null);
            xhr.onreadystatechange = function () {
              if (xhr.readyState != 4) return;
              if (xhr.readyState == 4 && xhr.status == 200) {
                // 处理正常的情况
                resolve(xhr.responseText);
              } else {
                // 处理异常情况
                reject('服务器错误');
              }
            };
          });
          return p; //这里必须返回一个promise对象
        }
        queryData('http://localhost:3004/data1')
          .then(function (data) {
            console.log(data);
          }, function (error) {
            console.log(error)
          });
        // ============================
        // 发送多个ajax请求并且保证顺序
        // queryData('http://localhost:3004/data')
        //   .then(function (data) {
        //     console.log(data)
        //     return queryData('http://localhost:3004/data1');
        //   })
        //   .then(function (data) {
        //     console.log(data);
        //     return queryData('http://localhost:3004/data2');
        //   })
        //   .then(function (data) {
        //     console.log(data)
        //   });
        //  对于发送多个ajax请求,通过then的方式变成线性关系,
        //  这里的 return出来的是一个新的promise对象,
        //  下一个then的调用者,就是上一个return出来的实例对象,
        //  并且then当中函数的参数data用与接收上一个异步任务的结果
      </script>
    </body>
    
    </html>
    使用服务器是01.api

    2.6-Promise的then方法参数中的函数的返回值

  • then参数中的函数返回值

  • then方法指定resolved状态和reject状态的回调函数

  • then返回值有几种

    • 可以返回一个promise对象 该实例对象会调用下一个then

    • 可以返回一个非promise对象 (普通值)下一个then会接收我们传过来的普通值

    • <!DOCTYPE html>
      <html lang="en">
      
      <head>
        <meta charset="UTF-8">
        <title>Document</title>
      </head>
      
      <body>
      
        <script type="text/javascript">
          /*
            then参数中的函数返回值
          */
          function queryData(url) {
            return new Promise(function (resolve, reject) {
              var xhr = new XMLHttpRequest();
              xhr.open('get', url);
              xhr.send(null);
              xhr.onreadystatechange = function () {
                if (xhr.readyState != 4) return;
                if (xhr.readyState == 4 && xhr.status == 200) {
                  // 处理正常的情况
                  resolve(xhr.responseText);
                } else {
                  // 处理异常情况
                  reject('服务器错误');
                }
              };
            });
          }
          queryData('http://localhost:3004/data')
            .then(function (data) {
              console.log(data)
              // return queryData('http://localhost:3004/data1');
              //这里的返回值是一个新的promise实例对象,这样下一个then就可以得到这个异步任务的结果
            })
          // .then(function (data) {
          //   console.log(data)
          //   return new Promise(function (resolve, reject) {
          //     setTimeout(function () {
          //       resolve("我是一个异步调用函数");
          //     }, 2000)
          //   });
          // })
          // .then(function (data) { //这里的then是由谁来调用呢?
          //   console.log(data) // 上一个then返回一个promise实例对象,
          //   //下一个then的参数就是上一个异步参数的结果
          //   return '普通字符串'; //retrun一个普通的字符串
          // })
          //问题来了 ,上一个then返回的是一个具体的值,下一个then是谁来调用呢?
          // .then(function (data) {
          //   console.log(data) //得到这个字符串,这里表明,
          //   //如果上一个then我们return一个具体的值而不是promise对象,
          //   //那么 下一个then就可以直接得到具体的值, 
          // })
      
          //如果上一个then返回的是一个具体的值,那么他会产生一个默认的promise对象
          //从而来调用下一个then
        </script>
      </body>
      
      </html>
      
      使用服务器是01.api

      2.7 -Promise 实例方法

    • prototype中的方法

      • .then()

        • 得到异步任务正确的结果

      • .catch()

        • 获取异常信息

      • finally()

        • 成功与否都会执行(不是正式标准)

        • <!DOCTYPE html>
          <html lang="en">
          
          <head>
            <meta charset="UTF-8">
            <title>Document</title>
          </head>
          
          <body>
          
            <script type="text/javascript">
              /*
                Promise常用API-实例方法
              */
              console.dir(Promise);
              function foo() {
                return new Promise(function (resolve, reject) {
                  setTimeout(function () {
                    resolve("success");
                    // reject('error'); 
                    // 注意:promise的状态是不可逆的
                  }, 100);
                })
              }
              // foo()
              //   .then(function (data) {
              //     console.log(data)   //正确
              //   })
              //   .catch(function (data) {
              //     console.log(data)   //捕获异常信息
              //   })
              //   .finally(function () {
              //     console.log('finished') //不管前面异步任务成功或者失败都会触发
              //   });
          
              // --------------------------
              // 两种写法是等效的
              // foo()
              //   .then(function (data) {         //成功回调
              //     console.log(data)
              //   }, function (data) {             //触发失败回调 
              //     console.log(data)
              //   })
              //   .finally(function () {
              //     console.log('finished') //不管前面异步任务成功或者失败都会触发
              //   });
            </script>
          </body>
          
          </html>

2.8 -Promise静态方法 --对象方法

  • .all()

Promise.all()并发处理多个异步任务,所有异步任务都执行完才能得到结果

  • Promise.all方法接受一个数组作参数,数组中的对象(p1、p2、p3)均为promise实例(如果不是一个promise,该项会被用Promise.resolve`转换为一个promise)。它的状态由这三个promise实例决定

  • <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
    </head>
    
    <body>
    
      <script type="text/javascript">
        /*
          Promise常用API-对象方法
        */
        // console.dir(Promise)
        function queryData(url) {
          return new Promise(function (resolve, reject) {
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function () {
              if (xhr.readyState != 4) return;
              if (xhr.readyState == 4 && xhr.status == 200) {
                // 处理正常的情况
                resolve(xhr.responseText);
              } else {
                // 处理异常情况
                reject('服务器错误');
              }
            };
            xhr.open('get', url);
            xhr.send(null);
          });
        }
    
        var p1 = queryData('http://localhost:3005/a1');
        var p2 = queryData('http://localhost:3005/a2');
        var p3 = queryData('http://localhost:3005/a3');
    
        Promise.all([p1, p2, p3]).then(function (result) {
          console.log(result) //所有的条件完成才有结果
        })
      </script>
    </body>
    
    </html>
    //使用服务器 06.api

  • 应用场景比如:

  • 用户点击按钮,会弹出一个弹出对话框,对话框中有两部分数据呈现,这两部分数据分别是不同的后端接口获取的数据。

    弹框弹出后的初始情况下,就让这个弹出框处于数据加载中的状态,当这两部分数据都从接口获取到的时候,才让这个数据加载中状态消失。让用户看到这两部分的数据。

    那么此时,我们就需求这两个异步接口请求任务都完成的时候做处理,所以此时,使用Promise.all方法,就可以轻松的实现

  • .race()

  • Promise.race方法同样接受一个数组作参数。当p1, p2, p3中有一个实例的状态发生改变(变为fulfilledrejected),p的状态就跟着改变。并把第一个改变状态的promise的返回值,传给p的回调函数

  • 首先我们知道race的用法是多个Promise实例谁先返回就输出谁, 用这个特性我们可以测试接口的响应速度(造一个n秒执行的定时器, 超过n秒就resolve的promise).

    又或者, 超过2秒给用户一个提醒网络状况不佳等, 那我们就可以做一个2秒的定时器reject即可

  • Promise.race()并发处理多个异步任务,只要有一个异步任务完成就能得到结果

  • <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
    </head>
    
    <body>
    
      <script type="text/javascript">
        /*
          Promise常用API-对象方法
        */
        // console.dir(Promise)
        function queryData(url) {
          return new Promise(function (resolve, reject) {
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function () {
              if (xhr.readyState != 4) return;
              if (xhr.readyState == 4 && xhr.status == 200) {
                // 处理正常的情况
                resolve(xhr.responseText);
              } else {
                // 处理异常情况
                reject('服务器错误');
              }
            };
            xhr.open('get', url);
            xhr.send(null);
          });
        }
    
        var p1 = queryData('http://localhost:3005/a1');
        var p2 = queryData('http://localhost:3005/a2');
        var p3 = queryData('http://localhost:3005/a3');
        // var p3 = new Promise((resolve ,reject) => {
        //       setTimeout(function () {
        //         reject("请求太慢了!")
        //       },500)
        // })
      
        Promise.race([p1, p2, p3]).then(function (result) {
          console.log(result) //最先返回就有结果
        }).catch((result) => {
          console.log(result); // 捕获错误
        })
        // 脚下留心
        // p1.then( res => {
        //   console.log(res)
        // })
        // p2.then( res => {
        //   console.log(res)
        // })
      </script>
    </body>
    
    </html>
    //使用服务器 06.api

  • 脚下留心:

  • all和race传入的数组中如果有会抛出异常的异步任务,那么只有最先抛出的错误会被捕获,并且是被then的第二个参数或者后面的catch`捕获;但并不会影响数组中其它的异步任务的执行。

3 -axios概述与基本用法

3.1 axios 概述

  • 基于promise用于浏览器和node.js的http客户端

  • 支持浏览器和node.js

  • 支持promise

  • 能拦截请求和响应

  • 自动转换JSON数据

  • 能转换请求和响应数据

3.2 axios基础用法

demo 07
使用服务器api10 

 <script type="text/javascript" src="js/axios.js"></script>
  <script type="text/javascript">
    axios.get('http://localhost:3007/adata').then(function (res) {
      // 注意data属性是固定的用法,用于获取后台的实际数据
      console.log(res)
      console.log(res.data)
    })
  </script>

3.3 axios传递参数

  • get和 delete请求传递参数

    • 通过传统的url 以 ? 的形式传递参数

    • restful 形式传递参数 /

    • 通过params 形式传递参数 注意前端使用params传递参数,服务器用query接收

  • post 和 put 请求传递参数

    • 通过选项传递参数

    • 通过 URLSearchParams 传递参数

    • //使用服务器10.api
        //demo11
          # 1-1 发送get 请求   
       <script type="text/javascript" src="js/axios.js"></script>
        <script type="text/javascript">
         //1.1传统方式---通过传统的url  以 ? 的形式传递参
          axios.get('http://localhost:3007/axios?id=123').then(function (res) {
            console.log(res.data)
          })
        </script>
      
          # 1-2  restful 形式传递参数 
          //1.2restful风格
          axios.get('http://localhost:3007/axios/123').then(function (res) {
            console.log(res.data)
          })
      	# 1-3  通过params  形式传递参数 
            axios.get('http://localhost:3007/axios', {
            params: { //axios专门提供的,服务器接口它使用的传统url的接口(query形式获取参数)
              id: 789  //这种是比较方便的
            }
          }).then(function (res) {
            console.log(res.data)
          })
      	# 2.axios delete 请求传参     传参的形式和 get 请求一样,同样可以使用get的三种方式
          axios.delete('http://localhost:3007/axios', {
            params: {
              id: 111
            }
          }).then(function (res) {
            console.log(res.data)
          })
      
      	# 3  axios 的 post 请求
          # 3.1  通过选项传递参数--post方式请求传参--json格式的
          axios.post('http://localhost:3007/axios', {
            uname: 'lisi',
            pwd: 123
          }).then(function (res) {
            console.log(res.data)
          })
      	# 3.2  通过 URLSearchParams  传递参数  post方式请求传参 --表单字符串格式的
          var params = new URLSearchParams(); //表单形式的参数 
          params.append('uname', 'zhangsan');
          params.append('pwd', '123456');
          axios.post('http://localhost:3007/axios', params).then(function (res) {
            console.log(res.data)
          })
      
      
       	#4.1 axios put 请求传参   和 post 请求一样  请求传参---json格式
          axios.put('http://localhost:3007/axios/123', {
            uname: 'lisi',
            pwd: 123456
          }).then(function (res) {
            console.log(res.data)
          })
      
      	#4.2 axios put 请求传参   和 post 请求一样  请求传参---表单字符串格式
      	var params = new URLSearchParams(); //表单形式的参数 
          params.append('uname', 'zhangsan');
          params.append('pwd', '1234567890');
          axios.put('http://localhost:3007/axios/123', params).then(function (res) {
            console.log(res.data)
          })

      3.4 -axios响应结果与全局配置

    • //demo09  
        //使用服务器10.api
      	
      	<script type="text/javascript" src="js/axios.js"></script>
          <script type="text/javascript">
            /*
            axios 响应结果与全局配置
          */
            // axios.get('http://localhost:3007/axios-json').then(function (res) {
            //   console.log(res);
            //   console.log(res.data.uname); //json不需要转换了,axios自动帮我们转化
            // });
      
            // axios全局配置
            // 配置请求的基准URL地址---发送请求时只写路径就可以了
            // axios.defaults.baseURL = 'http://localhost:3007/';
            // 配置超时时间
            // axios.defaults.timeout = 2500;
            // 配置请求头信息 注意:跨域是需要后台配置,允许携带mytoken
            // axios.defaults.headers['mytoken'] = 'helloworld';
            // axios.get('axios-json').then(function (res) {
            //   console.log(res.data.uname);
            // });
          </script>

      3.5 -axios 拦截器

    • 请求拦截器

      • 请求拦截器的作用是在请求发送前进行一些操作

      • 例如在每个请求体里加上token,统一做了处理如果以后要改也非常容易

    • 响应拦截器

      • 响应拦截器的作用是在接收到响应后进行一些操作

      • 例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页

      • // demo10
        //使用服务器10.api
        <script type="text/javascript" src="js/axios.js"></script>
          <script type="text/javascript">
            /*
              axios拦截器
            */
            //请求拦截器
            axios.interceptors.request.use(function (config) {
              console.log(config)
              //配置一个请求头,mytoken,类似于我们前面使用全局配置的方法配置请求头
              //只不过使用拦截器更加灵活,比入我们可以通过config获取url,给特定的url配置请求头
              config.headers.mytoken = 'hello';
        
              return config; //必须返回config
            }, function (err) { //用来处理错误信息
              console.log(err)
            })
            //响应拦截器
            // axios.interceptors.response.use(function (res) {
            //   // 设置res接收我们返回的数据res.data
            //   var res = res.data;
            //   return res; //返回data
            // }, function (err) {
            //   console.log(err) //对请求错误做点什么    
            // })
        
        
            axios.get('http://localhost:3007/adata').then(function (data) {
              // console.log(data)
              console.log(data.data)
            })
          </script>

4-async 和 await

4.1 概述

  • async/await是ES7引入的新语法,可以更加方便的进行异步操作

  • async作为一个关键字放到函数前面

    • 任何一个async函数都会隐式返回一个promise

  • await关键字只能在使用async定义的函数中使用

    • await后面可以直接跟一个 Promise实例对象

    • await函数不能单独使用

  • async/await 让异步代码看起来、表现起来更像同步代码

  • async await基础用法:

  1. 下方代码的运行结果是什么?

  2.  <script>
          function a() {
            return 'a 已经OK!';
          }
          function b() {
            setTimeout(() => {
              return 'b 已经OK!';
            }, 1000);
          }
          function c() {
            return 'c 已经OK!';
          }
    
          function run() {
            console.log(a());
            console.log(b());
            console.log(c());
          }
          run();
        </script>
  3. 将b()方法按照下列方式进行改造:

  4. function b () {
            return new Promise((resolve, reject)  =>{
                setTimeout(() => {
                    resolve("b 已经Ok!")
                }, 1000);
            })
       }
       此时发现打印结果不再是undefine而是一个Promise对象,

    使用async await 方法进行修饰

  5.  async function run () {
         console.log(a());
         console.log(await b());
         console.log(c());
       }
       run ()

    4.2 配合axios共同使用:

//服务器10.api
// demo11
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>

  <body>
    <script type="text/javascript" src="js/axios.js"></script>
    <script type="text/javascript">
      axios.defaults.baseURL = 'http://localhost:3007';
      // //传统方法
      axios.get('adata').then(function (res) {
        console.log(res.data);
      });

      // 核心:async await如何处理异步任务
      // 首先封装一个函数,这个函数的前写上async关键字
      // 其次在函数的内部通过await的方式处理异步的任务
      // await后面可以跟一个promise实例对象,所以在promise当中我们可以处理具体的异步任务,
      // awit前面通过通过返回值的形式得到异步的结果,这样就不在需要then和回调函数
      // 此外,还有一个细节,async返回值是一个新的promise对象
      // 任何一个async函数都会隐式返回一个promise   我们可以使用then 进行链式编程

      // 注意细节,await后面要跟一个promise实例对象

      async function queryData() {
        var res = await axios.get('adata'); //await后面是一个实例对象,
        //此时就不需要then了
        //console.log(ret) //得到请求结果
        return res.data; //返回数据 ,返回之后,在调用函数的时候在通过then得到这个返回值
      }
      // queryData()
      queryData().then(function (data) {
        console.log(data); //这里的值是通过queryData函数return来的结果
      });
    </script>
  </body>
</html>

4.3 async await处理多个请求的用法

  • 对于多个请求有时需要保证请求的顺序,比入第一个请求的结果作为第二个请求的参数来进行传递

  • //使用服务器15.api
    // demo12
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
    </head>
    <body>
      
      <script type="text/javascript" src="js/axios.js"></script>
      <script type="text/javascript">
        /*
          async/await处理多个异步任务
        */
        axios.defaults.baseURL = 'http://localhost:3008';
    
        async function queryData() {
          var info = await axios.get('async1');
          var ret = await axios.get('async2?info=' + info.data);
          return ret.data;
        }
    
        queryData().then(function(data){
          console.log(data)
        })
      </script>
    </body>
    </html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gao_xu_sheng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值