• luffy-(8)


    内容概览

    • 短信注册接口
    • 登录前台
    • 注册前台
    • redis介绍
    • python操作redis
    • redis连接池

    短信注册接口

    短信注册前端会通过post请求发送:手机号,验证码,密码---->{mobile:13812312312,code:8888,password:123123}
    后端路由:127.0.0.1:8000/api/vi/userinfo/user/register

    视图类
    class UserView(ViewSet):
    
        @action(methods=['POST'], detail=False)
        def register(self, request):
            ser = UserRegisterSerializer(data=request.data)
            ser.is_valid(raise_exception=True)
            ser.save()
            return APIResponse(msg='注册成功')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    序列化类
    class UserRegisterSerializer(serializers.ModelSerializer):
        code = serializers.CharField()
    
        class Meta:
            model = UserInfo
            fields = ['mobile', 'code', 'password']
    
        def validate(self, attrs):
            # 1. 验证code是否正确
            code = attrs.get('code')
            mobile = attrs.get('mobile')
            old_code = cache.get(f'sms_code_{mobile}')  # 取出存放在内存中的验证码
            if not (old_code == code or '8888'):  # 在测试阶段使用一个通用的验证码
                raise APIException('验证码错误')
            # 2. 如果验证码正确,需要做存入数据库前的准备:剔除code字段,将username设置为手机号
            attrs.pop('code')
            attrs['username'] = mobile
            return attrs
    
        def create(self, validated_data):  # 由于密码需要加密,所以需要重写create方法
            user = UserInfo.objects.create_user(**validated_data)  # **打散传入,使用create_user会将传入的password加密
            return user
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    登录前台

    登录分为多方式登录(用户名/手机号/邮箱+密码)与短信登录(验证码)

    Login.vue
    <template>
      <div class="login">
        <div class="box">
          <i class="el-icon-close" @click="close_login">i>
          <div class="content">
            <div class="nav">
              <span :class="{active: login_method === 'is_pwd'}"
                    @click="change_login_method('is_pwd')">密码登录span>
              <span :class="{active: login_method === 'is_sms'}"
                    @click="change_login_method('is_sms')">短信登录span>
            div>
            <el-form v-if="login_method === 'is_pwd'">
              <el-input
                  placeholder="用户名/手机号/邮箱"
                  prefix-icon="el-icon-user"
                  v-model="username"
                  clearable>
              el-input>
              <el-input
                  placeholder="密码"
                  prefix-icon="el-icon-key"
                  v-model="password"
                  clearable
                  show-password>
              el-input>
    
              <el-button type="primary" @click="handleMulLogin">登录el-button>
            el-form>
            <el-form v-if="login_method === 'is_sms'">
              <el-input
                  placeholder="手机号"
                  prefix-icon="el-icon-phone-outline"
                  v-model="mobile"
                  clearable
                  @blur="check_mobile">
              el-input>
              <el-input
                  placeholder="验证码"
                  prefix-icon="el-icon-chat-line-round"
                  v-model="sms"
                  clearable>
                <template slot="append">
                  <span class="sms" @click="send_sms">{{ sms_interval }}span>
                template>
              el-input>
    
              <el-button type="primary" @click="handleSmsLogin">登录el-button>
            el-form>
            <div class="foot">
              <span @click="go_register">立即注册span>
            div>
          div>
        div>
      div>
    template>
    
    <script>
    export default {
      name: "Login",
      data() {
        return {
          username: '',
          password: '',
          mobile: '',
          sms: '',
          login_method: 'is_pwd',
          sms_interval: '获取验证码',
          is_send: false,
        }
      },
      methods: {
        close_login() {
          this.$emit('close')
        },
        go_register() {
          this.$emit('go')
        },
        change_login_method(method) {
          this.login_method = method;
        },
        check_mobile() {
          if (!this.mobile) return;
          if (!this.mobile.match(/^1[3-9][0-9]{9}$/)) {
            this.$message({
              message: '手机号有误',
              type: 'warning',
              duration: 1000,
              onClose: () => {
                this.mobile = '';
              }
            });
            return false;
          }
          this.is_send = true;
        },
        send_sms() {
    
          if (!this.is_send) return;
          this.is_send = false;
          let sms_interval_time = 60;
          this.sms_interval = "发送中...";
          let timer = setInterval(() => {
            if (sms_interval_time <= 1) {
              clearInterval(timer);
              this.sms_interval = "获取验证码";
              this.is_send = true;
            } else {
              sms_interval_time -= 1;
              this.sms_interval = `${sms_interval_time}秒后再发`;
            }
          }, 1000);
          this.$axios.get(this.$settings.BASE_URL + 'userinfo/user/send_sms/?mobile=' + this.mobile).then(
              res => {
                this.$message({
                  message: res.data.msg,
                  type: 'success'
                });
              }
          )
        },
    
        // 多方式登录
        handleMulLogin(){
          if(this.username && this.password){  // 判断用户名与密码是否不为空
            this.$axios.post(this.$settings.BASE_URL+ 'userinfo/user/mul_login/',{
              username:this.username,
              password:this.password
            }).then(res=>{
              if (res.data.code===100){  // 如果状态码是100表示登录成功,将用户名、token、用户头像保存到本地
                this.$cookies.set('token', res.data.token)
                this.$cookies.set('username', res.data.username)
                this.$cookies.set('icon', res.data.icon)
                // 关闭登录模态框
                this.$emit('close')
              } else{
                this.$message({
                  message: res.data.msg,
                  type:'error'
                })
              }
            })
          } else {
            this.$message({
                  message: '用户名或密码不能为空',
                  type:'warning'
                })
          }
        },
        // 短信登录
        handleSmsLogin(){
          if (this.mobile && this.sms){
            this.$axios.post(this.$settings.BASE_URL + 'userinfo/user/mobile_login/',{
              mobile: this.mobile,
              code: this.sms
            }).then(res=>{
              if (res.data.code ===100) {
                this.$cookies.set('token', res.data.token)
                this.$cookies.set('username', res.data.username)
                this.$cookies.set('icon', res.data.icon)
                this.$emit('close')
              } else {
                this.$message({
                  message: res.data.msg,
                  type:'error'
                })
              }
            })
          } else{
            this.$message({
                  message: '手机号或验证码不能为空',
                  type:'warning'
                })
          }
        }
      }
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    Header.vue

    在登录后需要将主页的登录注册按钮替换为用户名和注销

    <template>
      <div class="header">
        <div class="slogan">
          <p>老男孩IT教育 | 帮助有志向的年轻人通过努力学习获得体面的工作和生活p>
        div>
        <div class="nav">
          <ul class="left-part">
            <li class="logo">
              <router-link to="/">
                <img src="../assets/img/head-logo.svg" alt="">
              router-link>
            li>
            <li class="ele">
              <span @click="goPage('/free-course')" :class="{active: url_path === '/free-course'}">免费课span>
            li>
            <li class="ele">
              <span @click="goPage('/actual-course')" :class="{active: url_path === '/actual-course'}">实战课span>
            li>
            <li class="ele">
              <span @click="goPage('/light-course')" :class="{active: url_path === '/light-course'}">轻课span>
            li>
          ul>
    
          <div class="right-part">
            
            <div v-if="!this.username">
              <span @click="put_login">登录span>
              <span class="line">|span>
              <span @click="put_register">注册span>
            div>
            <div v-else>
              <span @click="put_login">{{ username }}span>
              <span class="line">|span>
              
              <span @click="logout">注销span>
            div>
            <Login v-if="is_login" @close="close_login" @go="put_register">Login>
            <Register v-if="is_register" @close="close_register" @go="put_login">Register>
    
          div>
        div>
      div>
    
    template>
    
    <script>
    import Login from "@/components/Login";
    import Register from "@/components/Register";
    
    export default {
      name: "Header",
      data() {
        return {
          url_path: sessionStorage.url_path || '/',
          is_login: false,
          is_register: false,
          username: ''
        }
      },
      methods: {
        goPage(url_path) {
          // 已经是当前路由就没有必要重新跳转
          if (this.url_path !== url_path) {
            // 传入的参数,如果不等于当前路径,就跳转
            this.$router.push(url_path)
          }
          sessionStorage.url_path = url_path;
        },
        goLogin() {
          this.loginShow = true
        },
        put_login() {
          this.is_login = true;
          this.is_register = false;
        },
        put_register() {
          this.is_login = false;
          this.is_register = true;
        },
        close_login() {
          this.is_login = false;
          this.username = this.$cookies.get('username')
        },
        close_register() {
          this.is_register = false;
        },
        logout() {
          this.$cookies.remove('username')
          this.$cookies.remove('token')
          this.$cookies.remove('icon')
          this.username = ''
        }
      },
    
      created() {
        sessionStorage.url_path = this.$route.path
        this.url_path = this.$route.path
        this.username = this.$cookies.get('username')  // 创建页面时检查cookies中是否有用户名
      },
      components: {
        Login,
        Register
      }
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105

    注册前台

    <template>
      <div class="register">
        <div class="box">
          <i class="el-icon-close" @click="close_register">i>
          <div class="content">
            <div class="nav">
              <span class="active">新用户注册span>
            div>
            <el-form>
              <el-input
                  placeholder="手机号"
                  prefix-icon="el-icon-phone-outline"
                  v-model="mobile"
                  clearable
                  @blur="check_mobile">
              el-input>
              <el-input
                  placeholder="密码"
                  prefix-icon="el-icon-key"
                  v-model="password"
                  clearable
                  show-password>
              el-input>
              <el-input
                  placeholder="验证码"
                  prefix-icon="el-icon-chat-line-round"
                  v-model="sms"
                  clearable>
                <template slot="append">
                  <span class="sms" @click="send_sms">{{ sms_interval }}span>
                template>
              el-input>
    
              <el-button type="primary" @click="handleRegister">注册el-button>
            el-form>
            <div class="foot">
              <span @click="go_login">立即登录span>
            div>
          div>
        div>
      div>
    template>
    
    <script>
    export default {
      name: "Register",
      data() {
        return {
          mobile: '',
          password: '',
          sms: '',
          sms_interval: '获取验证码',
          is_send: false,
        }
      },
      methods: {
        close_register() {
          this.$emit('close', false)
        },
        go_login() {
          this.$emit('go')
        },
        check_mobile() {
          if (!this.mobile) return;
          if (!this.mobile.match(/^1[3-9][0-9]{9}$/)) {
            this.$message({
              message: '手机号有误',
              type: 'warning',
              duration: 1000,
              onClose: () => {
                this.mobile = '';
              }
            });
            return false;
          }
          // 判断手机号是否存在
          this.$axios.get(this.$settings.BASE_URL + 'userinfo/user/mobile/?mobile=' + this.mobile).then(res=>{
            if (res.data.code ===100 ){
              this.mobile = ''
              this.$message({
                message: '该手机号已经注册',
                type:'warning'
              });
              return  // 函数结束掉
            }
          })
          this.is_send = true;
        },
        send_sms() {
          if (!this.is_send) return;
          this.is_send = false;
          let sms_interval_time = 60;
          this.sms_interval = "发送中...";
          let timer = setInterval(() => {
            if (sms_interval_time <= 1) {
              clearInterval(timer);
              this.sms_interval = "获取验证码";
              this.is_send = true; // 重新回复点击发送功能的条件
            } else {
              sms_interval_time -= 1;
              this.sms_interval = `${sms_interval_time}秒后再发`;
            }
          }, 1000);
          // 发送短信
          this.$axios.get(this.$settings.BASE_URL + 'userinfo/user/send_sms/?mobile=' + this.mobile).then(res=>{
            this.$message({
              message: res.data.msg,
              type: 'success'
            })
          })
        },
        // 注册
        handleRegister(){
          if (this.mobile && this.sms && this.password){
            this.$axios.post(this.$settings.BASE_URL + 'userinfo/user/register/', {
              mobile: this.mobile,
              code: this.sms,
              password: this.password
            }).then(res=>{
              if (res.data.code === 100){
                // 跳转到登录
                this.$emit('go')
              }else{
                this.$message({
              message: res.data.msg, 
              type: 'error'
            })
              }
            })
          } else{
            this.$message({
              message: '不能有空',
              type: 'error'
            })
          }
        }
      }
    }
    script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140

    redis介绍

    # 介绍 c s 架构的软件
    	redis:非关系型数据库【存数据的地方】nosql数据库,内存存储,速度非常快,可以持久化【数据从内存同步到硬盘】,数据类型丰富【5大数据类型:字符串,列表,哈希(字典),集合,有序集合】,key-value形式存储【根本没有表的结构,相当于咱们的字典】
        
        -nosql:指非关系型数据库:1 不限于SQL  2 没有sql
        
    # redis 为什么这么快
    	-1 高性能的网络模型:IO多路复用的epoll模型,承载住非常高的并发量
        -2 纯内存操作,避免了很多io
        -3 单线程架构,避免了线程间切换的消耗
        	-6.x之前:单线程,单进程
        	-6.x以后,多线程架构,数据操作还是使用单线程,别的线程做数据持久化,其他操作
    
    # redis 应用场景(了解)
    	1 当缓存数据库使用,接口缓存,提高接口响应速度
        	-请求进到视图---》去数据查询[多表查询,去硬盘取数据:速度慢]----》转成json格式字符串---》返回给前端
            -请求进到视图---》去redis[内存]----》取json格式字符串---》返回给前端
        2 做计数器:单线程,不存在并发安全问题
        	-统计网站访问量
            -个人站点浏览量
            -文章阅读量
            
        3 去重操作:集合
        4 排行榜:有序集合
        	-阅读排行榜
            -游戏金币排行榜
            
        5 布隆过滤器
        6 抽奖
        7 消息队列
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    redis安装
    # 开源软件:使用c语言写的---【编译型语言,在操作系统运行,要编译成可执行文件,由于采用了IO多路复用的epoll模型,所以它不支持windows,只有linux操作系统支持epoll】
    
    # 微软官方根据源代码修改,编译成可执行的安装包,
    	-版本没有最新
    
    # 官网:https://redis.io/
    	-下载完是源代码:c语言源码 :https://redis.io/download/#redis-stack-downloads
        -最稳定:6.x
        -最新7.x
    
    # 中文网:http://redis.cn/download.html
    	-上面最新只到5.x
        
        
    # win版本下载地址
        # 最新5.x版本 https://github.com/tporadowski/redis/releases/
        # 最新3.x版本 https://github.com/microsoftarchive/redis/releases
    	下载完一路下一步即可,具体可参照:https://www.cnblogs.com/liuqingzheng/p/9831331.html
        
        
    # win装完会有redis服务
    	-启动服务,手动停止
        -客户端链接:redis-cli -h 127.0.0.1 -p 6379
        -简单命令:
        	set name lqz
            get name
            ping
            
        -停掉服务:
        	-去win服务点关闭
            -客户端关闭:shutdown
        
     
    
    #mysql 服务端
    #mysql客户端
    	-navicate
        -命令窗口cmd
        -python操作
        
        
    # redis 服务器端
    # redis 客户端
    	-redis-cli
        -图形化工具:redis-destop-management
        -python操作
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    python操作redis

    # 下载redis模块
    pip install redis
    
    # 导入使用
    from redis import Redis
    conn = Redis(host='localhost', port=6379)  # 实例化得到对象
    conn.set('name', 'xxx')  # 设置key、value
    res = conn.get('name')  # 通过key获取value
    print(res)  # b'xxx'
    conn.close()  # 关闭连接
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    redis连接池

    import redis
    import time
    
    from threading import Thread
    
    """直接连接"""
    # def get_name_from_redis():
    #     conn = redis.Redis(host='localhost', port=6379)
    #     print(conn.get('name'))
    #     conn.close()
    #
    # for i in range(100):
    #     t = Thread(target=get_name_from_redis)
    #     t.start()
    #
    # time.sleep(3)  # 等待线程执行结束
    
    
    """使用连接池连接"""
    from POOL import pool
    def get_name_from_redis():
        # 创建一个连接池,需要保证它是单例,全局只有一个pool对象;可以使用模块导入的方式实现单例,也可以通过参数传入
        # pool = redis.ConnectionPool(max_connections=10, host='localhost', port=6379)
        conn = redis.Redis(connection_pool=pool)  # 每次执行一次会从翅中取出一个连接
        print(conn.get('name'))
        conn.close()
    
    
    for i in range(10):
        t = Thread(target=get_name_from_redis)
        t.start()
    
    time.sleep(3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • POOL.py
    import redis
    
    pool = redis.ConnectionPool(max_connections=10, host='localhost', port=6379)
    """直接导入模块:from POOL import pool"""
    
    • 1
    • 2
    • 3
    • 4

    练习
    • 使用线程异步发送短信
      @staticmethod
      def thread_send_sms(mobile):
          code = get_code()  # 获取随机验证码
          cache.set(f'sms_code_{mobile}', code)  # 保存验证码到内存中
          send_sms_by_phone(mobile, code)
      
      @action(methods=['GET'], detail=False)
      def send_sms(self, request):
          mobile = request.query_params.get('mobile')
          if re.match(r'^1[3-9]\d{9}$', mobile):  # 通过正则校验手机号
              t = Thread(target=self.thread_send_sms, args=(mobile,))  # 通过线程异步发送短信
              t.start()
              return APIResponse(msg='发送短信成功')
          else:
              return APIResponse(msg='手机号不合法', code=102)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
  • 相关阅读:
    代码随想录算法训练营Day60 | 84. 柱状图中最大的矩形
    Java项目如何防止SQL注入的四种方案
    字节跳动后端面经(18)
    【NOWCODER】- Python:输入输出
    swift加载h5页面空白
    uniapp 滑动页面至某个元素或顶部
    来自北大算法课的Leetcode题解:7. 整数反转
    Hooks的使用
    避坑手册 | JAVA编码中容易踩坑的十大陷阱
    resilience4j 重试源码分析以及重试指标采集
  • 原文地址:https://blog.csdn.net/AL_QX/article/details/127849100