Michael Wang пре 6 година
родитељ
комит
3e201c6b9e
3 измењених фајлова са 63 додато и 62 уклоњено
  1. 16 13
      public/index.html
  2. 13 32
      src/main.js
  3. 34 17
      src/views/index.vue

+ 16 - 13
public/index.html

@@ -8,19 +8,22 @@
   <link rel="icon" href="<%= BASE_URL %>favicon.ico">
   <title>photo-upload</title>
   <script>
-    var firstStepKey = false
-    document.addEventListener("keydown", function (e) {
-      console.log(e);
-      if (e.ctrlKey && e.shiftKey && e.code === 'KeyU') {
-        window.firstStepKey = true;
-        setTimeout(() => {
-          window.firstStepKey = false
-        }, 1000);
-      }
-      if (window.firstStepKey && e.ctrlKey && e.shiftKey && e.code === 'KeyP') {
-        nodeRequire('electron').remote.getCurrentWindow().toggleDevTools();
-      }
-    });
+    (function () {
+      // 按Ctrl+Shift+U,放开U,在一秒内再按Ctrl+Shift+P,可以调出开发者工具
+      let firstStepKey = false
+      document.addEventListener("keydown", function (e) {
+        console.log(e);
+        if (e.ctrlKey && e.shiftKey && e.code === 'KeyU') {
+          firstStepKey = true;
+          setTimeout(() => {
+            firstStepKey = false
+          }, 1000);
+        }
+        if (firstStepKey && e.ctrlKey && e.shiftKey && e.code === 'KeyP') {
+          nodeRequire('electron').remote.getCurrentWindow().toggleDevTools();
+        }
+      });
+    })()
   </script>
   <script type="text/javascript">
     if (typeof (require) != "undefined") {

+ 13 - 32
src/main.js

@@ -14,8 +14,11 @@ Vue.use(ElementUI);
 
 const qmInstance = axios.create({});
 let wk_token;
+// 正在处理的请求数
 window.requestInProcessingTotal = 0;
+// 并发的总错误数
 window.faceppConcurrencyErrorNum = 0;
+// 每分钟并发错误的数量
 window.faceppConcurrencyErrorNumPerMinute = 0;
 let faceppConCurrencyErrorArray = [];
 qmInstance.interceptors.request.use(
@@ -41,6 +44,7 @@ qmInstance.interceptors.request.use(
   }
 );
 
+// 计算每分钟的并发错误数
 function calcErrorPerMinute(now) {
   const valid = faceppConCurrencyErrorArray.filter(
     t => now - t < 3 * 60 * 1000
@@ -59,6 +63,7 @@ qmInstance.interceptors.response.use(
   response => {
     window.requestInProcessingTotal--;
 
+    // 相当于timer的作用
     const now = Date.now();
     calcErrorPerMinute(now);
     return response;
@@ -72,6 +77,7 @@ qmInstance.interceptors.response.use(
       if (error.response.data.error_message) {
         console.log(error.response.data.error_message);
         if (error.response.data.error_message.toLowerCase().includes("limit")) {
+          // 这是facepp并发错误的response特征
           const now = Date.now();
           faceppConCurrencyErrorArray.push(now);
           if (faceppConCurrencyErrorArray.length > 200) {
@@ -88,7 +94,7 @@ qmInstance.interceptors.response.use(
     if (
       error.response.data.code === "403"
       //  &&
-      // error.response.data.desc === "no login."
+      // error.response.data.desc === "no login." // 线上可能是 token is wrong
     ) {
       wk_token = null;
       localStorage.removeItem("rootOrgId");
@@ -126,45 +132,20 @@ qmInstance.defaults.timeout = 10000; //超时时间
 qmInstance.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest"; //标识这是一个 ajax 请求
 
 axiosRetry(qmInstance, {
-  retries: 3,
+  retries: 5, // 重试5次
   retryCondition: err => {
-    // debugger;
-    console.log(`error status code: ${err.response.status} and retry ...`);
+    // 根据err的特征来执行请求,目前是全部请求
+    console.log(
+      `below error status code: ${err.response.status} and retry ...`
+    );
     console.log(err);
+    console.log();
     return true;
   }
 });
 
 Vue.prototype.$http = qmInstance;
 
-// var errorNum = 0; //403次数
-// Vue.http.interceptors.push(function(request, next) {
-//   var user_token = localStorage.getItem("user_token");
-//   if (user_token) {
-//     request.headers.set("user_token", localStorage.getItem("user_token"));
-//   }
-//   next(function(response) {
-//     if (response.status == 403 && response.body && response.body.desc) {
-//       clearInterval(global_.pageTimer["uploadTimer"]); //停止定时器
-//       localStorage.removeItem("rootOrgId");
-//       localStorage.removeItem("userName");
-//       localStorage.removeItem("user_token");
-//       if (errorNum == 0) {
-//         errorNum++;
-//         this.$alert("登录失效,请重新登录!", "提示", {
-//           showClose: false,
-//           confirmButtonText: "确定",
-//           callback: action => {
-//             this.$router.push({ path: "/login" });
-//           }
-//         });
-//       }
-//     } else if (response.status != 200) {
-//       console.log(response);
-//     }
-//   });
-// });
-
 new Vue({
   router,
   render: h => h(App)

+ 34 - 17
src/views/index.vue

@@ -160,8 +160,9 @@ export default {
       this.processQueueSingle(taskQueue);
     },
     processQueueSingle(taskQueue100) {
-      // 并发处理请求,可在控制台查看请求峰值
+      // 并发处理请求
       // CONCURRENCY = new Date().getHours() < 6 ? 9 : 5;
+      // 根据并发错误频率来决定下一次多少并发
       if (window.faceppConcurrencyErrorNumPerMinute < 7 && CONCURRENCY < 9) {
         CONCURRENCY++;
       } else {
@@ -175,7 +176,7 @@ export default {
         } else {
           console.log(results);
           if (this.successNum + this.errorNum < this.allNum) {
-            console.log("处理完100张图片了,3秒后继续...");
+            console.log("处理完100张图片了,0.5秒后继续...间隔提供给GC");
             const delay = Date.now() - this.startProcessTime < 10000 ? 0 : 500; // 如果有跳过的图标则不等待0.5秒
             setTimeout(this.processQueue, delay);
           } else {
@@ -193,6 +194,7 @@ export default {
         .basename(studentPhotoPath)
         .replace(fileSuffix, ""); //文件名就是身份证号码
 
+      // 根据用户输入来跳过部分图片
       if (this.lessThanBaseID(identityNumber)) {
         this.finishOnePhotoSuccess("跳过处理", studentPhotoPath);
         this.skipNum++;
@@ -200,14 +202,17 @@ export default {
       }
       const photoFile = fs.readFileSync(studentPhotoPath);
       const rootOrgId = localStorage.getItem("rootOrgId");
-      this.reqNum = window.requestInProcessingTotal;
-      this.faceppConcurrencyErrorNum = window.faceppConcurrencyErrorNum;
-      this.faceppConcurrencyErrorNumPerMinute =
-        window.faceppConcurrencyErrorNumPerMinute;
 
-      this.processSpeed =
-        (this.successNum + this.errorNum - this.skipNum) /
-        (Date.now() - this.startProcessTime);
+      {
+        // 执行过程中的元信息
+        this.reqNum = window.requestInProcessingTotal;
+        this.faceppConcurrencyErrorNum = window.faceppConcurrencyErrorNum;
+        this.faceppConcurrencyErrorNumPerMinute =
+          window.faceppConcurrencyErrorNumPerMinute;
+        this.processSpeed =
+          (this.successNum + this.errorNum - this.skipNum) /
+          (Date.now() - this.startProcessTime);
+      }
 
       //生成新名称
       const upyunPhotoPath = (() => {
@@ -217,26 +222,32 @@ export default {
         return rootOrgId + "/" + identityNumber + "/" + md5Hash + fileSuffix;
       })();
 
+      // 核心流程:
+      // 1. get studentId from ecs
+      // 2. get faceToken from facepp
+      // 3. get faceSetToken from ecs
+      // 4. add faceToken to faceSetToken
+      // 5. save photo to upyun
+      // 6. 根据以上信息,保存到服务器
+      // 每一步出错都会保存到错误日志
       try {
-        let studentFaceInfo = await this.getStudentInfo(
-          rootOrgId,
-          identityNumber
-        );
+        let studentId = await this.getStudentId(rootOrgId, identityNumber);
         let faceToken = await this.detectFace(photoFile);
         if (this.faceSetToken == undefined) {
+          // 超过8000会重新获取
           this.faceSetToken = await this.getFaceSetToken();
         }
         await this.addFaceToSet(this.faceSetToken, faceToken);
 
+        await this.saveImageToUpyun({ upyunPhotoPath, photoFile });
         const photoInfo = {
-          studentId: studentFaceInfo.student.id,
+          studentId: studentId,
           faceSetToken: this.faceSetToken,
           faceToken: faceToken,
           studentPhotoPath: studentPhotoPath,
           rootOrgId: rootOrgId,
           upyunPhotoPath
         };
-        await this.saveImageToUpyun({ upyunPhotoPath, photoFile });
         await this.saveStudentFaceInfoByPut(photoInfo);
         this.finishOnePhotoSuccess("处理成功", studentPhotoPath);
       } catch (err) {
@@ -244,7 +255,7 @@ export default {
         this.finishOnePhotoFail(err, studentPhotoPath);
       }
     },
-    async getStudentInfo(rootOrgId, identityNumber) {
+    async getStudentId(rootOrgId, identityNumber) {
       return new Promise((resolve, reject) => {
         this.$http
           .get(
@@ -256,7 +267,7 @@ export default {
           .then(res => {
             var studentFaceInfo = res.data;
             if (studentFaceInfo.student && studentFaceInfo.student.id) {
-              resolve(studentFaceInfo);
+              resolve(studentFaceInfo.student.id);
             } else {
               reject("查询身份证不存在");
             }
@@ -311,6 +322,12 @@ export default {
             //     res.data.face_added
             //   }, res.data.face_count: ${res.data.face_count}`
             // );
+            if (res.data.face_added !== 1) {
+              reject(
+                "faceToken加入faceSetToken失败: face_added为" +
+                  res.data.face_added
+              );
+            }
             if (res.data.face_count > 8000) {
               window.DB.updateFaceSet(faceset_token, res.data.face_count).then(
                 () => {