Forráskód Böngészése

登录、开考限流

Michael Wang 4 éve
szülő
commit
57492c9e15

+ 17 - 0
src/features/Login/Login.vue

@@ -145,6 +145,7 @@ import {
 import { isElectron } from "@/utils/util";
 import GeeTest from "./GeeTest";
 import GlobalNotice from "./GlobalNotice";
+import { tryLimit } from "@/utils/tryLimit";
 
 // 检测devtools.  仅在chrome 72+ 有效。
 let element = new Image();
@@ -490,6 +491,22 @@ export default {
         return;
       }
       this.loginBtnLoading = true;
+
+      const limitResult = await tryLimit({ action: "login", limit: 500 });
+      if (!limitResult) {
+        createLog({
+          currentPage: "登录页面--login clicked",
+          action: "登录被限流",
+        });
+        this.$Modal.warning({
+          title: "提示",
+          content: "网络繁忙,请稍后再试。",
+        });
+        await new Promise((resolve) => setTimeout(() => resolve(), 3000));
+        this.loginBtnLoading = false;
+        return;
+      }
+
       const before = Date.now();
 
       // console.log(this.captchaObj.getValidate());

+ 25 - 71
src/features/OnlineExam/OnlineExamList.vue

@@ -31,19 +31,13 @@
             >
               <i-button
                 class="qm-primary-button qm-primary-button-padding-fix"
-                :disabled="disableTheCourse(course) || spinShow"
-                :title="disableTheCourse(course) ? disableReason(course) : ''"
-                @click="
-                  () => {
-                    if (isEpcc) {
-                      raceEnter(course);
-                    } else {
-                      enterExam(course);
-                    }
-                  }
+                :disabled="
+                  disableTheCourse(course) || spinShow || enterButtonClicked
                 "
+                :title="disableTheCourse(course) ? disableReason(course) : ''"
+                @click="raceEnter(course)"
               >
-                进入考试{{ isEpcc && countdown > 0 ? `(${countdown})` : "" }}
+                进入考试{{ countdown > 0 ? `(${countdown})` : "" }}
               </i-button>
               <i-poptip
                 v-if="!isEpcc"
@@ -106,7 +100,7 @@ import {
 } from "vuex";
 const { mapState, mapMutations } = createNamespacedHelpers("examHomeModule");
 import CheckComputer from "./CheckComputer";
-import axios from "axios";
+import { tryLimit } from "@/utils/tryLimit";
 
 export default {
   name: "EcsOnlineList",
@@ -132,6 +126,7 @@ export default {
       cid: null,
       shouldShowCheckEnvModal: false,
       countdown: 0,
+      enterButtonClicked: false,
     };
   },
   computed: {
@@ -164,7 +159,7 @@ export default {
         return "当前时间不在考试开放时间范围";
       } else if (course.allowExamCount < 1) {
         return "无剩余考试次数";
-      } else if (this.isEpcc && this.countdown > 0) {
+      } else if (this.countdown > 0) {
         return "请稍后点击";
       } else {
         return "";
@@ -174,66 +169,24 @@ export default {
       return (
         !this.courseInBetween(course) ||
         course.allowExamCount < 1 ||
-        (this.isEpcc && this.countdown > 0)
+        this.countdown > 0
       );
     },
     async raceEnter(course) {
       const minutesAfterCourseStart = Math.floor(
-        moment(this.now).diff(moment(course.startTime), "seconds") / 30
+        moment(this.now).diff(moment(course.startTime), "seconds") / 60
       );
 
-      window._hmt.push([
-        "_trackEvent",
-        "在线考试列表页面",
-        "摇号进入考试-courseId-" + course.examId,
-        minutesAfterCourseStart < 120
-          ? minutesAfterCourseStart / 2 + "分进行点击"
-          : "60分后进行点击",
-      ]);
-
-      let serverOk = false;
-      let serverPass = false;
-      try {
-        const res = await axios.get(
-          "https://rate-limit.qmth.com.cn/rateLimit",
-          { timeout: 5 * 1000 }
-        );
-        serverOk = true;
-        serverPass = res.data.pass;
-      } catch (error) {
-        console.log(error);
-        window._hmt.push([
-          "_trackEvent",
-          "在线考试列表页面",
-          "获取rateLimit失败",
-        ]);
-      }
-
-      const successRatePerMinute = [0.5, 0.5, 0.5, 0.5, 1]; // 30秒步进
+      this.enterButtonClicked = true;
+      const limitResult = await tryLimit({ action: "startExam", limit: 100 });
+      this.enterButtonClicked = false;
 
-      let idx = 0;
-      if (minutesAfterCourseStart < 0) {
-        idx = 0;
-      } else if (
-        minutesAfterCourseStart >= 0 &&
-        minutesAfterCourseStart < successRatePerMinute.length
-      ) {
-        idx = minutesAfterCourseStart;
-      } else {
-        idx = successRatePerMinute.length - 1;
-      }
-      if (
-        (serverOk && serverPass) ||
-        (!serverOk && Math.random() > 1 - successRatePerMinute[idx])
-      ) {
-        window._hmt.push([
-          "_trackEvent",
-          "在线考试列表页面",
-          "摇号进入考试-courseId-" + course.examId,
-          minutesAfterCourseStart < 120
-            ? minutesAfterCourseStart / 2 + "分进入"
-            : "60分后进入",
-        ]);
+      if (limitResult) {
+        window._hmt.push(["_trackEvent", "在线考试列表页面", "摇号进入考试"]);
+        this.logger({
+          action: "在线考试列表页面",
+          detail: "限流-" + minutesAfterCourseStart + "分进入",
+        });
 
         this.enterExam(course);
         // return true;
@@ -241,14 +194,15 @@ export default {
         window._hmt.push([
           "_trackEvent",
           "在线考试列表页面",
-          "摇号进入考试-courseId-" + course.examId,
-          minutesAfterCourseStart < 120
-            ? minutesAfterCourseStart / 2 + "分被限流"
-            : "60分后被限流",
+          "摇号进入考试-限流",
         ]);
+        this.logger({
+          action: "在线考试列表页面",
+          detail: "限流-" + minutesAfterCourseStart + "分被限流",
+        });
         this.$Modal.warning({
           title: "提示",
-          content: "考试人员过多,请稍等2分钟再试。",
+          content: "网络繁忙,请稍后再试。",
           onOk: () => {
             clearInterval(this.countdownInterval);
             this.countdown = 10;

+ 37 - 0
src/utils/tryLimit.js

@@ -0,0 +1,37 @@
+import axios from "axios";
+import { createLog } from "./logger";
+
+export async function tryLimit({ action, limit = 100 }) {
+  let res = null;
+  let serverPass = false;
+  try {
+    res = await axios.get(
+      `https://tcc.qmth.com.cn/rate_limit/prod/${action}/${limit}`,
+      { timeout: 5 * 1000 }
+    );
+    serverPass = res.data.pass;
+
+    if (!serverPass) {
+      // 休眠 1 ~ 5 秒 再试
+
+      const sleepTime = Math.random() * 4 + 1;
+      console.log({ sleepTime, now: Date.now() });
+      await new Promise((resolve) => setTimeout(resolve, sleepTime * 1000));
+      console.log({ sleepTime, now: Date.now() });
+      res = await axios.get(
+        `https://tcc.qmth.com.cn/rate_limit/prod/${action}/${limit}`,
+        { timeout: 5 * 1000 }
+      );
+      serverPass = res.data.pass;
+      createLog({
+        action: "限流后自动重试",
+        detail: serverPass ? "进入" : "依然限流",
+      });
+    }
+  } catch (error) {
+    console.log(error);
+    window._hmt.push(["_trackEvent", "在线考试列表页面", "获取rateLimit失败"]);
+  }
+
+  return serverPass;
+}