服务端接入
更新时间:2026-10-09
服务端接入
验证码服务的整体通讯过程:
- 业务客户端集成验证码 SDK,拉起验证并完成人机验证;
- 验证通过后客户端获得验证码 token 数据
stk; - 前端将
stk传给业务服务端; - 业务服务端拿到
stk进行 AES 加密,生成加密数据; - 调用验证码服务端接口发起验签(二次校验);
- 获取接口返回结果并解密判断是否校验通过。
1.接口调用流程
完成客户端接入后,还需要在服务端调用verifystk接口,发起验证请求。
- 前端验证通过拿到 token数据 stk;
- 前端随业务请求将 stk 传给业务服务端。传递方式由业务约定,例如 JSON 请求体。
- 业务服务端将包含 stk 的 JSON 数据进行 AES 加密,得到请求体的 data。
- 服务端生成当前秒级时间戳 ts,根据 ak + ts + sk 计算 tk。
- 使用 POST 请求调用 /v1/webapi/verint/verifystk 发起验签(二次校验)。
-
检查 HTTP 状态及外层 code:
- 仅当 HTTP 状态为 200 且 code 为 0 时,解密响应的 data;
- 解析解密后的 JSON,仅当 pass 为布尔值 true 时,认定本次二次校验通过。
2. 接口地址
| 项目 | 值 |
|---|---|
| 域名(主) | https://sec-captcha-cloud.baidu.com/ |
| 域名(备用) | https://sec-captcha-cloud-1.baidu.com/ |
3. 二次校验请求
- AK:业务访问标识,用于接口鉴权。
- SK:服务端密钥,用于计算 tk 及请求、响应数据的 AES 加解密。仅保存在业务服务端,不应下发到浏览器或小程序,也不应写入公开代码或日志。
- stk:前端验证完成后取得的 token。前端验证通过不等于服务端校验通过,业务需完成二次校验。
- 二次校验 stk 合法性:
Plain Text
1. stk 有效期为 1 分钟;
2. 只能验证一次, 从而防止重放攻击,超过1次认为校验不通过。
3.1 请求方法
| 项目 | 内容 |
|---|---|
| 请求 URL | https://sec-captcha-cloud.baidu.com/v1/webapi/verint/verifystk |
| 请求方法 | POST |
| Content-Type | application/json; charset=utf-8 |
3.2 Query 参数
| 参数 | 类型 | 必选 | 说明 |
|---|---|---|---|
| ak | string | 是 | 控制台分配的 AK |
| ts | string | 是 | 当前 Unix 时间戳的十进制字符串,单位为秒。每次请求重新生成,并保证服务端时间同步 |
| tk | string | 是 | CRC32(UTF8(ak + ts + sk))的无符号十进制字符串 |
- tk 使用 CRC32 IEEE 算法,按顺序直接拼接 AK、请求中的原始 ts 字符串和 SK,不添加分隔符,不添加参数名。
- 计算结果按无符号 32 位整数转为十进制字符串,取值范围为 0~4294967295。
Plain Text
1签名原文 = ak + ts + sk
2tk = unsigned_decimal(CRC32_IEEE(UTF8(签名原文)))
- 请求中的 ts 必须与计算 tk 时使用的字符串一致。验证码服务端会检查时间戳有效性,允许的时间窗口以服务端配置为准。
3.3 Body 参数
| 参数 | 类型 | 必选 | 说明 |
|---|---|---|---|
| data | string | 是 | 将下述明文 JSON 按 第 6 节 加密后得到的标准 Base64 字符串 |
加密前的明文结构:
| 字段 | 类型 | 必选 | 说明 |
|---|---|---|---|
| stk | string | 是 | 前端传入的完整 token,不自行解析、截断或改写 |
| scene | string | 否 | 业务场景,例如 login |
| data | object | 否 | 业务补充参数,例如用户标识 |
JSON
1{
2 "stk": "前端返回的完整 stk",
3 "scene": "login",
4 "data": {
5 "uid": "12345"
6 }
7}
外层请求体只有加密后的 data;内层 data 是明文中的业务补充对象,两者含义不同。请使用语言自带的 JSON 序列化方法生成明文,避免手工拼接或将补充对象再次序列化为字符串。
JSON
1{
2 "data": "加密后得到的 Base64 字符串"
3}
3.4 请求示例
将 AK、TS、TK 和 ENCRYPTED_DATA 替换为本次请求对应的实际值。ENCRYPTED_DATA 必须由同一业务的 SK 加密得到,不可直接复用历史示例密文。
Bash
1AK='替换为控制台分配的 AK'
2TS='替换为当前秒级时间戳'
3TK='替换为本次请求计算得到的 tk'
4ENCRYPTED_DATA='替换为本次请求的加密数据'
5
6curl --request POST --connect-timeout 3 --max-time 5 \
7 "https://sec-captcha-cloud.baidu.com/v1/webapi/verint/verifystk?ak=${AK}&ts=${TS}&tk=${TK}" \
8 --header 'Content-Type: application/json; charset=utf-8' \
9 --data "{\"data\":\"${ENCRYPTED_DATA}\"}"
4. 二次校验响应
4.1 外层响应
| 字段 | 类型 | 说明 |
|---|---|---|
| code | int | 0 表示接口调用成功;非 0 表示接口异常。code = 0 不代表验证码验证通过 |
| msg | string | 接口状态或错误信息,不用于判断验证码是否通过 |
| data | string/null | 成功时为加密结果,异常时可能为 null。加解密方式见 第 6 节 |
| log_id | string | 请求标识,排查问题时可提供给技术支持 |
成功响应结构示例(data 为占位说明,不能用于解密):
JSON
1{
2 "code": 0,
3 "msg": "success",
4 "data": "接口返回的 Base64 加密结果",
5 "log_id": "请求标识"
6}
4.2 解密后的结果
| 字段 | 类型 | 说明 |
|---|---|---|
| pass | bool | 最终校验结果;true 为通过,false 为未通过。判断逻辑为 is_cap && !is_spam |
| is_spam | bool | 是否判定为作弊或风险请求 |
| is_cap | bool | token 中的一次验证是否成功 |
| score | int | 威胁评分,越大表示机器可能性越大;可能省略,省略时按 0 处理 |
| detail | array of string | 判定依据;可能省略,省略时按空数组处理 |
| ctype | string | 验证码类型,供排查或统计使用 |
| level | int | 验证码难度,供排查或统计使用 |
校验通过的结果示例:
JSON
1{
2 "pass": true,
3 "is_spam": false,
4 "is_cap": true,
5 "ctype": "b_track_match",
6 "level": 0
7}
一次验证成功,但二次校验判定为风险请求的结果示例:
JSON
1{
2 "pass": false,
3 "is_spam": true,
4 "is_cap": true,
5 "score": 5,
6 "detail": ["b"],
7 "ctype": "b_track_match",
8 "level": 0
9}
detail 中的 "b" 表示 stk 时间戳超过有效期。其他判定依据以验证码服务端返回为准。业务应以 pass 作最终判断,不通过 is_cap 或 score 自行替代。
4.3 异常响应
JSON
1{
2 "code": 80005,
3 "msg": "DataDecodeFalied",
4 "data": null,
5 "log_id": "91ce771bf9424a5b5104c23b5b310451"
6}
接口异常可能同时返回非 200 HTTP 状态;不要尝试解密 null 或空字符串。记录 HTTP 状态、code、msg 和 log_id 以便排查。
5. 错误码
| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 80000 | AK 不存在或不可用 | 检查业务申请的 AK 是否正确 |
| 80001 | ts 格式非法 | 使用秒级 Unix 时间戳的十进制字符串 |
| 80002 | ts 超过允许的时间窗口 | 检查服务器时间同步,重新生成 ts 和 tk |
| 80003 | tk 校验失败 | 核对拼接顺序、CRC32 算法、无符号十进制格式及 AK/SK 配对 |
| 80004 | 请求体解析失败或参数缺失 | 检查 Content-Type、JSON 结构及外层 data |
| 80005 | data 解密或解析失败 | 核对 SK、ECB 模式、零填充、Base64 和明文 JSON |
| 80006 | data 格式非法 | 检查数据格式,以实际返回为准 |
| 80007 | 服务端生成校验结果失败 | 按业务异常流程处理;持续出现时联系技术支持 |
6. 加解密及多语言示例
6.1 Go 加密解密示例
使用 github.com/forgoer/openssl v1.1.1。该库为 Go 实现,无需系统 OpenSSL。示例中的 any 需要 Go 1.18+。
Go
1package main
2
3import (
4 "bytes"
5 "encoding/base64"
6 "encoding/json"
7 "fmt"
8
9 "github.com/forgoer/openssl"
10)
11
12var (
13 // 分配的 ak
14 appkey = "********************************"
15 // 分配的 sk
16 secretKey = "********************************"
17)
18
19type VerifyStkDataInfo struct {
20 Stk string `json:"stk"` // stoken
21 Scene string `json:"scene"` // 场景
22 Data map[string]any `json:"data"` // 补充参数
23}
24
25func main() {
26 checkData := VerifyStkDataInfo{
27 Stk: "1_MdZSn67LRFth2xgszhZlOo48tNmALNS-dWgPXjhZsEOIsI2so0UAiPstmgncypxE9oLyVTCbjIzcXZNuYhR_Fniwm-rFhalsKuQgi3MaNhSVziFbfwYv-TRgjqeC04R-C4hVgezfRffC0_XZ4Ibj1FL5egwObRbt4ETJvDtGDynjNZJxfdYsT30Pm3k_VT9ESiV4r9B6IQSt8ZG6P7OfchFRLCrKBB1VByWsRtOHk1s=",
28 Scene: "login", // 可选
29 Data: map[string]any{"uid": 111}, // 可选
30 }
31
32 // post 接口 body 数据
33 // {
34 // "data": "nzeVu9Zm4uodH/Z+DI9iUu8li317Eig/AdfQtEGRwv6v4Foa9lU24n1avH5qPM/Z0ZnAPgryXbldpYP1jLuAppe2YvKbH+Oz+qyJQAxv1mKQXh4HNRxUC02E79KEaytwiDB3txaHoimDogGPsk5RtdIV8VKZJqCmgo0xIahMBTFPyUmO7OS2mUwLDjNuTRAqHD4QMqB4xI/V2SmmS6P/LCQTSdKPkB9/ptr6kuFT+ke/K81UJWPD42PdHlarbytkBG1fzyWaM9r03lmsBacorIQppXzUsP5G6i/0V2BhVwc3aMympAz8VNeYe5oxdxO7QHGr93TBR5jJURrOr6JUYrlmYB6eYXe7h707FjCE26z19HjPpQjJMvSNU+ALX9w3KJKL1vxvJMUxJflO2kPq+Q=="
35 // }
36 data, err := assembleData(checkData)
37 fmt.Println("加密后 Post Body 的 data:", data)
38 if err != nil {
39 panic(err)
40 }
41
42 /////////////////////////////////////////////
43 // 接口返回 data 解密
44 // {
45 // "data": "+avB7i2I+4LxPZHZt0qm7KhWvvwmUt+sFbcEWE4MANB3LzIdjAbhGvZngYk86aOrsBGZ10I0nfJZTJg6Wmkxbg==",
46 // "code": 0,
47 // "msg": ""
48 // }
49 decData, err := aesDecode("+avB7i2I+4LxPZHZt0qm7KhWvvwmUt+sFbcEWE4MANB3LzIdjAbhGvZngYk86aOrsBGZ10I0nfJZTJg6Wmkxbg==", secretKey)
50 if err != nil {
51 panic(err)
52 }
53 // 接口返回 data 解密 decData: {"pass":false,"is_spam":true,"is_cap":true,"detail":["b"]}
54 fmt.Println("接口返回 data 解密 decData:", decData)
55}
56
57// assembleData 组装data
58func assembleData(checkData VerifyStkDataInfo) (string, error) {
59 encodeCheckData, errEncodeCheckData := json.Marshal(checkData)
60 if errEncodeCheckData != nil {
61
62 return "", errEncodeCheckData
63 }
64 data, errAesEncode := aesEncode(encodeCheckData, secretKey)
65 if errAesEncode != nil {
66 return "", errAesEncode
67 }
68
69 return data, nil
70}
71
72// aesEncode Aes数据加密
73func aesEncode(data []byte, sk string) (string, error) {
74 encryptData, err := openssl.AesECBEncrypt(data, []byte(sk), openssl.ZEROS_PADDING)
75 if err != nil {
76 return "", err
77 }
78 return base64.StdEncoding.EncodeToString(encryptData), nil
79}
80
81// aesDecode Aes数据解密
82func aesDecode(data string, sk string) (string, error) {
83 resBase64Decode, err := base64.StdEncoding.DecodeString(data)
84 if err != nil {
85 return "", err
86 }
87 if len(resBase64Decode) == 0 || len(resBase64Decode)%16 != 0 {
88 return "", fmt.Errorf("invalid ciphertext length")
89 }
90 key := []byte(sk)
91 res, err := openssl.AesECBDecrypt(resBase64Decode, key, "")
92 if err != nil {
93 return "", err
94 }
95
96 return string(bytes.TrimRight(res, "\x00")), nil
97}
6.2 Java 加密解密示例
- pom 文件:
XML
1<?xml version="1.0" encoding="UTF-8"?>
2<project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <modelVersion>4.0.0</modelVersion>
6
7 <groupId>com.baidu.seccaptcha</groupId>
8 <artifactId>demo</artifactId>
9 <version>1.0-SNAPSHOT</version>
10
11 <properties>
12 <maven.compiler.source>17</maven.compiler.source>
13 <maven.compiler.target>17</maven.compiler.target>
14 </properties>
15 <dependencies>
16 <dependency>
17 <groupId>commons-codec</groupId>
18 <artifactId>commons-codec</artifactId>
19 <version>1.15</version>
20 </dependency>
21 <dependency>
22 <groupId>com.alibaba</groupId>
23 <artifactId>fastjson</artifactId>
24 <version>1.2.83</version>
25 </dependency>
26 </dependencies>
27</project>
- 加密、解密示例:
Java
1package com.baidu.seccaptcha;
2
3import com.alibaba.fastjson.JSONObject;
4import java.util.Base64;
5import java.util.HashMap;
6import java.util.Map;
7import javax.crypto.Cipher;
8import javax.crypto.spec.SecretKeySpec;
9
10public class AESUtils {
11 public static void main(String[] args) {
12 String sk = "****************";
13
14 JSONObject jsonObject = new JSONObject();
15 jsonObject.put("stk",
16 "1_quExwipacpBC4PukBSLtv5jUUi5CiKB3ZawBBie0ARfnwO9joJEUyG_GF6fJWxfd7tbM_z18crl8_k0Jq5WWLLEZ9f1tvACGv-rGSn-9MOftEf2VkOGDnGtptUjqMvqRL2YYgGTMdTNyMdjKD8461XMxaW7_EsSsP0yJEuZIKSGyrAZ_zKA2ZiY4ChktjobN");
17 jsonObject.put("scene", "login");
18 Map<String, String> data = new HashMap<>();
19 data.put("uid", "12345");
20 jsonObject.put("data", data);
21
22 String jsonString = jsonObject.toString();
23 System.out.println("jsonString: " + jsonString);
24
25 // 生成 接口 post body 加密数据
26 // {
27 // "data":"AfcZ8tUOXFcYzHF/jqSfyr47KjcZ1UWCp6nE0cOPAkMppbb+TYbPliKgBwII8UAd2P9mHgAyLRb59szFLl4BoocpwBiQJ6X4uVZWIhJuUDaFb0VT4Cey7DxnIS0CEWPddtGm6WKZMJQb1tYAHVeqIelFKOaWHkF0RNJG0CDhfKi2CQ+4F5Kf/IZF1Wv42BGjyFCtyVBaHRMPpYPXmQcvsNPRhaCTgkSwMoK2cc8REw01ahNO0iO1tqR2BYrdJHd6g8r/G8ioK4i2UbRCqAs+yskN9N/VDVH8XvGWwRkmF34S0PruH8DoDM3FNkAv9xmBy5F3J4SgYLVcdou1oOk+6w=="
28 // }
29 String encryptedData = AESUtils.AESEncode(jsonString, sk);
30 System.out.println("encryptedData: " + encryptedData);
31
32 // 接口 response 解密 示例
33 // {
34 // "data":
35 // "fzWbphJiHJIWLTihYn2wGZA5Er9/HSktAf4ycc0DRYNSW+9gN7vRlEzG+8DUjezdyF0RyMktwwURInZsDRwaUg==",
36 // "code": 0,
37 // "msg": ""
38 // }
39 String decryptedData = AESUtils.AESDecode(
40 "fzWbphJiHJIWLTihYn2wGZA5Er9/HSktAf4ycc0DRYNSW+9gN7vRlEzG+8DUjezdyF0RyMktwwURInZsDRwaUg==", sk);
41 System.out.println("decryptedData: " + decryptedData);
42
43 }
44
45
46 private static String AESEncode(String str, String key) {
47 String ret = "";
48 if (str != null && str.length() > 0) {
49 try {
50 Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
51 SecretKeySpec keyspec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
52 cipher.init(Cipher.ENCRYPT_MODE, keyspec);
53 //待加密内容的长度必须是16的倍数,如果不是16的倍数,就抛出IllegalBlockSizeException,补全加密内容。
54 //因此解密的时候,明文最后有可能出现一段特殊字符,这就是aes用于补全用的字符。用json解析使用明文前,
55 //移除末尾的零字节(\0)后再进行 JSON 解析。
56 byte[] dataBytes = str.getBytes("UTF-8");
57 int dataLength = dataBytes.length;
58 if (dataLength % 16 != 0) {
59 dataLength = dataLength + (16 - (dataLength % 16));
60 }
61 byte[] paddingBytes = new byte[dataLength];
62 System.arraycopy(dataBytes, 0, paddingBytes, 0, dataBytes.length);
63
64 byte[] encrypted = cipher.doFinal(paddingBytes);
65 ret = Base64.getEncoder().encodeToString(encrypted);
66 return ret;
67 } catch (Exception e) {
68 throw new IllegalStateException("AES encrypt failed", e);
69 }
70 }
71 throw new IllegalArgumentException("empty AES input");
72 }
73
74 private static String AESDecode(String str, String key) {
75 String ret = "";
76 if (str != null && str.length() > 0) {
77 try {
78 byte[] dataBytes = Base64.getDecoder().decode(str);
79 if (dataBytes.length == 0 || dataBytes.length % 16 != 0) {
80 throw new IllegalArgumentException("invalid ciphertext length");
81 }
82 Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
83 SecretKeySpec keyspec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
84 cipher.init(Cipher.DECRYPT_MODE, keyspec);
85 byte[] retBytes = cipher.doFinal(dataBytes);
86 int end = retBytes.length;
87 while (end > 0 && retBytes[end - 1] == 0) { end--; }
88 ret = new String(retBytes, 0, end, "UTF-8");
89 return ret;
90 } catch (Exception e) {
91 throw new IllegalStateException("AES decrypt failed", e);
92 }
93
94 }
95 throw new IllegalArgumentException("empty AES input");
96 }
97}
6.3 PHP 加密解密示例
通过 Encrypt 类和 OpenSSL 扩展实现加解密。本示例使用 AES-256-ECB,SK 必须为 32 字节。OPENSSL_ZERO_PADDING 仅关闭自动填充,需要手工补零。
PHP
1class Encrypt
2{
3 /**
4 * 用配置中的密钥,aes加密
5 * @param $str 加密前
6 * @param $key 密钥
7 * @return string 加密后
8 */
9 public static function aes_encode($str,$key)
10 {
11 if (strlen($key) !== 32) { throw new InvalidArgumentException("AES-256 requires a 32-byte key"); }
12 $paddedstr = $str;
13 $method = 'AES-256-ECB';
14 //aes block size is fixed 16.
15 if (strlen($str) % 16 != 0) {
16 $paddedstr = str_pad($str, strlen($str) + 16 - strlen($str) % 16, "\0");
17 }
18 $ciphertext = openssl_encrypt($paddedstr, $method, $key, $options=OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
19 if ($ciphertext === false) { throw new RuntimeException("AES encrypt failed"); }
20 return base64_encode($ciphertext);
21 }
22 /**
23 * 用配置中的密钥,aes解密
24 * @param $str 反解前
25 * @param $key 密钥
26 * @return string 反解后
27 */
28 public static function aes_decode($str,$key)
29 {
30 if (strlen($key) !== 32) { throw new InvalidArgumentException("AES-256 requires a 32-byte key"); }
31 $method = "AES-256-ECB";
32 $cipherText = base64_decode($str, true);
33 if ($cipherText === false || strlen($cipherText) === 0 || strlen($cipherText) % 16 !== 0) {
34 throw new InvalidArgumentException("invalid ciphertext");
35 }
36 $ret = openssl_decrypt($cipherText, $method, $key, $options=OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
37 if ($ret === false) { throw new RuntimeException("AES decrypt failed"); }
38 return rtrim($ret, chr(0));
39 }
40}
6.4 Python 示例
Python
1# -*- coding: utf-8 -*-
2from Crypto.Cipher import AES
3from base64 import b64encode, b64decode
4import json
5import zlib
6import time
7import requests
8
9class MyCrypt():
10 def __init__(self, key):
11 self.key = key.encode('utf-8')
12 self.mode = AES.MODE_ECB
13 self.padding = b'\0'
14
15 def encrypt(self, text):
16 """AES 加密;按 UTF-8 字节数补零。"""
17 cryptor = AES.new(self.key, self.mode)
18 data = text.encode('utf-8')
19 data += self.padding * (-len(data) % 16)
20 self.ciphertext = cryptor.encrypt(data)
21 return self.ciphertext
22
23 def decrypt(self, text):
24 """AES 解密;只移除末尾零字节。"""
25 if not text or len(text) % 16 != 0:
26 raise ValueError('invalid ciphertext length')
27 cryptor = AES.new(self.key, self.mode)
28 plain_text = cryptor.decrypt(text)
29 return plain_text.rstrip(b'\0').decode('utf-8')
30
31def calc_tk(ak, ts, sk):
32 return str(zlib.crc32((ak + ts + sk).encode('utf-8')) & 0xffffffff)
33
34if __name__ == '__main__':
35 # 用户申请的 AK
36 appid = '替换为控制台分配的 AK'
37 # 分给用户的 SK(仅保存在服务端)
38 appsecret = '********************************'
39 # 前端传递的完整 stk
40 stk = '替换为前端刚取得的完整 stk'
41 data = json.dumps({'stk': stk, 'scene': 'login',
42 'data': {'ip': '127.0.0.1', 'client_type': 'pc'}}, ensure_ascii=False)
43 ec = MyCrypt(appsecret)
44 encrpt_data = ec.encrypt(data)
45 decrpt_data = ec.decrypt(encrpt_data)
46 assert decrpt_data == data
47
48 # 组装 Query 和 JSON 请求体
49 timestamp = str(int(time.time()))
50 params = {'ak': appid, 'ts': timestamp, 'tk': calc_tk(appid, timestamp, appsecret)}
51 url = 'https://sec-captcha-cloud.baidu.com/v1/webapi/verint/verifystk'
52 r = requests.post(url, params=params,
53 json={'data': b64encode(encrpt_data).decode('ascii')}, timeout=5)
54 if r.status_code != 200:
55 raise RuntimeError('captcha HTTP error: %s' % r.status_code)
56 result = r.json()
57 if not isinstance(result, dict) or type(result.get('code')) is not int:
58 raise ValueError('invalid response envelope')
59 if result['code'] != 0:
60 raise RuntimeError('captcha API error: code=%s, msg=%s, log_id=%s' %
61 (result['code'], result.get('msg'), result.get('log_id')))
62 if not isinstance(result.get('data'), str) or not result['data']:
63 raise ValueError('missing encrypted response data')
64 check_data = json.loads(ec.decrypt(b64decode(result['data'], validate=True)))
65 if not isinstance(check_data, dict) or type(check_data.get('pass')) is not bool:
66 raise ValueError('missing or invalid pass field')
67 print('验证通过' if check_data['pass'] else '验证未通过')
7. 服务端容灾
服务端容灾部署:
- 需要客户在服务端集成二次校验流程时,注意对二次校验的接口进行异常处理;
- 当请求二次验证接口异常或响应状态非200时做出相应异常处理,保证不会因为接口请求超时或服务未响应而阻碍业务流程。
评价此篇文章
