Przeglądaj źródła

第三方商品服务-完善异常捕获

sunxbiao 5 miesięcy temu
rodzic
commit
f62e915e1d

+ 18 - 1
thirdPartyWares_service/src/main/java/com/bjtdba/thirdPartWares/controller/TaobaoCallback.java

@@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.GetMapping;
11 11
 import org.springframework.web.bind.annotation.RequestMapping;
12 12
 import org.springframework.web.bind.annotation.RestController;
13 13
 import org.springframework.web.servlet.ModelAndView;
14
+import org.springframework.web.util.UriComponentsBuilder;
14 15
 
15 16
 import java.io.IOException;
16 17
 import java.net.URLDecoder;
@@ -28,6 +29,8 @@ public class TaobaoCallback {
28 29
     private UserThirdDao userThirdDao;
29 30
     @Value("${TB.AUTH_REDIRECT_URI}")
30 31
     private String authRedirectUri;
32
+    @Value("${TB.AUTH_ERROR_REDIRECT_URI}")
33
+    private String authErrorRedirectUri;
31 34
 
32 35
     /**
33 36
      * 淘宝回调
@@ -37,12 +40,26 @@ public class TaobaoCallback {
37 40
     public ModelAndView getTaobaoAuthorizedLoginToken(String code, String state) throws IOException {
38 41
         String decodedState = "";
39 42
         if (state != null) {
43
+            System.err.println(state);
40 44
             decodedState = URLDecoder.decode(state, "UTF-8");
41 45
             // Base64 解码
42 46
             byte[] decodedBytes = Base64.getDecoder().decode(decodedState);
43 47
             decodedState = new String(decodedBytes, StandardCharsets.UTF_8);
44 48
         }
45
-        taobaoService.getTaobaoAuthorizedLoginToken(code, decodedState);
49
+        try {
50
+            taobaoService.getTaobaoAuthorizedLoginToken(code, decodedState);
51
+        } catch (RuntimeException e) {
52
+            // 1. 记录日志
53
+            System.err.println("淘宝API调用失败: " + e.getMessage());
54
+            // 2. 返回错误页面或错误信息
55
+            String redirectUrl = UriComponentsBuilder.fromUriString(authErrorRedirectUri)
56
+                    .queryParam("msg", e.getMessage())
57
+                    .build()
58
+                    .encode(StandardCharsets.UTF_8)
59
+                    .toUriString();
60
+
61
+            return new ModelAndView("redirect:" + redirectUrl);
62
+        }
46 63
         String viewName = "redirect:" + authRedirectUri;
47 64
 
48 65
         if (!decodedState.isEmpty()) {

+ 165 - 41
thirdPartyWares_service/src/main/java/com/bjtdba/thirdPartWares/service/impl/TaobaoServiceImpl.java

@@ -442,7 +442,7 @@ public class TaobaoServiceImpl implements TaobaoService {
442 442
 
443 443
     @Override
444 444
     public void getTaobaoAuthorizedLoginToken(String code, String state) throws IOException {
445
-        Map<String, String> params = new HashMap<String, String>();
445
+        Map<String, String> params = new HashMap<>();
446 446
         // 公共参数
447 447
         params.put("method", "taobao.top.auth.token.create");
448 448
         params.put("app_key", tbAppKey);
@@ -453,24 +453,92 @@ public class TaobaoServiceImpl implements TaobaoService {
453 453
         params.put("sign_method", "hmac");
454 454
         params.put("code", code);
455 455
         params.put("sign", SignTop.signTopRequest(params, tbkAppSecret, "hmac"));
456
+
456 457
         System.out.println("***************taobao.top.auth.token.create start *****************");
457
-        System.out.println(params.toString());
458
-        String a = SignTop.callApi(new URL("https://eco.taobao.com/router/rest"), params);
459
-        System.out.println("原始响应字符串: " + a);
460
-        JSONObject jsonObjects = JSONObject.parseObject(a);
461
-        System.out.println("解析为JSONObject后: " + jsonObjects.toJSONString());
462
-        System.out.println("***************taobao.top.auth.token.create* end****************");
463
-        Object token = JSONObject.parseObject(JSONObject.parseObject(jsonObjects.get("top_auth_token_create_response").toString()).get("token_result").toString()).get("access_token");
464
-        //备案
465
-        demo(token.toString(),state);
458
+        System.out.println(params);
459
+        String responseString;
460
+        try {
461
+            responseString = SignTop.callApi(new URL("https://eco.taobao.com/router/rest"), params);
462
+        } catch (IOException e) {
463
+            throw new RuntimeException("淘宝授权网络请求失败", e);
464
+        }
465
+        System.out.println("原始响应字符串: " + responseString);
466
+        if (responseString == null || responseString.trim().isEmpty()) {
467
+            throw new RuntimeException("淘宝授权响应为空");
468
+        }
469
+
470
+        JSONObject jsonObject;
471
+        try {
472
+            jsonObject = JSONObject.parseObject(responseString);
473
+        } catch (Exception e) {
474
+            throw new RuntimeException("淘宝授权响应JSON解析失败", e);
475
+        }
476
+        System.out.println("解析为JSONObject后: " + jsonObject.toJSONString());
477
+        System.out.println("*************** taobao.top.auth.token.create end *****************");
478
+
479
+        // 1. 检查淘宝业务错误
480
+        if (jsonObject.containsKey("error_response")) {
481
+            JSONObject error = jsonObject.getJSONObject("error_response");
482
+            String code_ = error.getString("code");
483
+            String msg = error.getString("msg");
484
+            String subMsg = error.getString("sub_msg");
485
+            throw new RuntimeException(String.format("淘宝授权业务错误 [code=%s, msg=%s, subMsg=%s]", code_, msg, subMsg));
486
+        }
487
+        // 2. 获取 top_auth_token_create_response
488
+        JSONObject createResp = jsonObject.getJSONObject("top_auth_token_create_response");
489
+        if (createResp == null) {
490
+            throw new RuntimeException("响应缺少 top_auth_token_create_response 字段");
491
+        }
492
+        // 3. 获取 token_result 字符串
493
+        String tokenResultStr = createResp.getString("token_result");
494
+        if (tokenResultStr == null || tokenResultStr.isEmpty()) {
495
+            throw new RuntimeException("token_result 字段为空");
496
+        }
497
+        // 4. 解析 token_result
498
+        JSONObject tokenResult;
499
+        try {
500
+            tokenResult = JSONObject.parseObject(tokenResultStr);
501
+        } catch (Exception e) {
502
+            throw new RuntimeException("token_result JSON解析失败: " + tokenResultStr, e);
503
+        }
504
+        // 5. 获取 access_token
505
+        String accessToken = tokenResult.getString("access_token");
506
+        if (accessToken == null || accessToken.isEmpty()) {
507
+            throw new RuntimeException("access_token 字段为空");
508
+        }
509
+
510
+        // 6. 备案
511
+        demo(accessToken, state);
466 512
     }
467 513
     //备案
468 514
     private void demo(String token,String state) throws IOException {
515
+//        if (state == null || state.trim().isEmpty()) {
516
+//            throw new RuntimeException("state 参数为空");
517
+//        }
518
+//
519
+//        String cleanState = state.trim();
520
+//        // 移除 UTF-8 BOM(如果存在)
521
+//        if (cleanState.startsWith("\uFEFF")) {
522
+//            cleanState = cleanState.substring(1);
523
+//        }
524
+
525
+        JSONObject stateObject;
526
+        try {
527
+            stateObject = JSONObject.parseObject(state);
528
+        } catch (Exception e) {
529
+            System.err.println("state 原始字符串长度: " + state.length());
530
+            System.err.println("state 前100字符: " + state.substring(0, Math.min(100, state.length())));
531
+            System.err.println("state 后100字符: " + state.substring(Math.max(0, state.length() - 100)));
532
+            // 可选:打印十六进制字节,用于排查编码问题
533
+            System.err.println("state 字节数组(hex): " + bytesToHex(state.getBytes(StandardCharsets.UTF_8)));
534
+            throw new RuntimeException("state 参数JSON解析失败: " + state, e);
535
+        }
536
+        String uid = stateObject.getString("uid");
537
+        if (uid == null) {
538
+            throw new RuntimeException("state 中缺少 uid 字段");
539
+        }
469 540
 
470
-        JSONObject stateObject = JSONObject.parseObject(state);
471
-
472
-        Map<String, String> params = new HashMap<String, String>();
473
-        // 公共参数
541
+        Map<String, String> params = new HashMap<>();
474 542
         params.put("method", "taobao.tbk.sc.publisher.info.save");
475 543
         params.put("app_key", tbAppKey);
476 544
         params.put("session", token);
@@ -478,39 +546,95 @@ public class TaobaoServiceImpl implements TaobaoService {
478 546
         params.put("timestamp", df.format(new Date()));
479 547
         params.put("format", "json");
480 548
         params.put("v", "2.0");
481
-        params.put("sign_method","hmac");
549
+        params.put("sign_method", "hmac");
482 550
         // 业务参数
483
-        // 会员
484
-        // params.put("inviter_code","RQHQ8Z");
485
-        // 渠道
486
-        params.put("inviter_code","BCS4V5");
487
-        params.put("info_type","1");
488
-        params.put("note","幸福_"+stateObject.get("uid"));
489
-        // 签名参数
551
+        params.put("inviter_code", "BCS4V5");   // 渠道邀请码
552
+        params.put("info_type", "1");
553
+        params.put("note", "幸福_" + uid);
490 554
         params.put("sign", SignTop.signTopRequest(params, tbkAppSecret, "hmac"));
491
-        // 请用API
492
-        System.out.println("***************taobao.tbk.sc.publisher.info.save start *****************");
493
-        System.out.println(params.toString());
494
-        String callApi = SignTop.callApi(new URL("https://eco.taobao.com/router/rest"), params);
495
-        // 打印原始字符串
496
-        System.out.println("原始响应字符串: " + callApi);
497
-        JSONObject jsonObjects = JSONObject.parseObject(callApi);
498
-        // 打印解析后的JSONObject(使用toString,但通常toString没有格式化,我们可以用toJSONString来美化)
499
-        System.out.println("解析为JSONObject后: " + jsonObjects.toJSONString());
500
-        System.out.println("***************taobao.tbk.sc.publisher.info.save end *****************");
501
-        String data = JSONObject.parseObject(jsonObjects.get("tbk_sc_publisher_info_save_response").toString()).get("data").toString();
502
-        Object account_name = JSONObject.parseObject(data).get("account_name");
503
-        Object relation_id = JSONObject.parseObject(data).get("relation_id");
555
+
556
+        System.out.println("*************** taobao.tbk.sc.publisher.info.save start *****************");
557
+        System.out.println(params);
558
+
559
+        String responseString;
560
+        try {
561
+            responseString = SignTop.callApi(new URL("https://eco.taobao.com/router/rest"), params);
562
+        } catch (IOException e) {
563
+            throw new RuntimeException("淘宝备案网络请求失败", e);
564
+        }
565
+        System.out.println("原始响应字符串: " + responseString);
566
+
567
+        if (responseString == null || responseString.trim().isEmpty()) {
568
+            throw new RuntimeException("淘宝备案响应为空");
569
+        }
570
+
571
+        JSONObject jsonObject;
572
+        try {
573
+            jsonObject = JSONObject.parseObject(responseString);
574
+        } catch (Exception e) {
575
+            throw new RuntimeException("淘宝备案响应JSON解析失败: " + responseString, e);
576
+        }
577
+        System.out.println("解析为JSONObject后: " + jsonObject.toJSONString());
578
+        System.out.println("*************** taobao.tbk.sc.publisher.info.save end *****************");
579
+
580
+        // 1. 检查淘宝业务错误
581
+        if (jsonObject.containsKey("error_response")) {
582
+            JSONObject error = jsonObject.getJSONObject("error_response");
583
+            String code = error.getString("code");
584
+            String msg = error.getString("msg");
585
+            String subMsg = error.getString("sub_msg");
586
+            throw new RuntimeException(String.format("淘宝备案业务错误 [code=%s, msg=%s, subMsg=%s]", code, msg, subMsg));
587
+        }
588
+
589
+        // 2. 获取 tbk_sc_publisher_info_save_response
590
+        JSONObject saveResp = jsonObject.getJSONObject("tbk_sc_publisher_info_save_response");
591
+        if (saveResp == null) {
592
+            throw new RuntimeException("响应缺少 tbk_sc_publisher_info_save_response 字段");
593
+        }
594
+
595
+        // 3. 获取 data 字段(可能是 JSONObject 或 JSONArray?根据文档通常是对象)
596
+        Object dataObj = saveResp.get("data");
597
+        if (dataObj == null) {
598
+            throw new RuntimeException("data 字段为空");
599
+        }
600
+
601
+        JSONObject dataJson;
602
+        if (dataObj instanceof JSONObject) {
603
+            dataJson = (JSONObject) dataObj;
604
+        } else {
605
+            try {
606
+                dataJson = JSONObject.parseObject(dataObj.toString());
607
+            } catch (Exception e) {
608
+                throw new RuntimeException("data 字段无法转换为JSONObject: " + dataObj, e);
609
+            }
610
+        }
611
+
612
+        String accountName = dataJson.getString("account_name");
613
+        String relationId = dataJson.getString("relation_id");
614
+        if (accountName == null || relationId == null) {
615
+            throw new RuntimeException("备案返回数据中缺少 account_name 或 relation_id");
616
+        }
617
+
618
+        // 4. 保存到数据库
504 619
         UserThird userThird = new UserThird();
505
-        userThird.setUid((String) stateObject.get("uid"));
506
-        userThird.setPid(relation_id.toString());
507
-        userThird.setPid_name(account_name.toString());
508
-        userThird.setCreate_time(new Date().getTime()+"");
620
+        userThird.setUid(uid);
621
+        userThird.setPid(relationId);
622
+        userThird.setPid_name(accountName);
623
+        userThird.setCreate_time(String.valueOf(System.currentTimeMillis()));
509 624
         userThird.setType("5");
510 625
         userThirdDao.inster(userThird);
511
-        System.out.println(jsonObjects);
512
-        //return s;
513 626
 
627
+        System.out.println("备案成功,uid=" + uid + ", relation_id=" + relationId);
628
+
629
+    }
630
+
631
+    // 辅助方法:字节数组转十六进制
632
+    private static String bytesToHex(byte[] bytes) {
633
+        StringBuilder sb = new StringBuilder();
634
+        for (byte b : bytes) {
635
+            sb.append(String.format("%02x", b));
636
+        }
637
+        return sb.toString();
514 638
     }
515 639
 
516 640
     /**

+ 3 - 1
thirdPartyWares_service/src/main/resources/application-dev.yml

@@ -39,4 +39,6 @@ eureka:
39 39
 
40 40
 TB.REDIRECTURI: https://testapi.hxxfb.com/taobao_service/taobaoService/loginToken
41 41
 
42
-TB.AUTH_REDIRECT_URI: https://testapi.hxxfb.com/taobao_service/baichuan.html
42
+TB.AUTH_REDIRECT_URI: https://testapi.hxxfb.com/taobao_service/baichuan.html
43
+
44
+TB.AUTH_ERROR_REDIRECT_URI: https://testapi.hxxfb.com/taobao_service/auth_error.html

+ 3 - 1
thirdPartyWares_service/src/main/resources/application-pro.yml

@@ -39,4 +39,6 @@ eureka:
39 39
 
40 40
 TB.REDIRECTURI: https://api.hxxfb.com/taobao_service/taobaoService/loginToken
41 41
 
42
-TB.AUTH_REDIRECT_URI: https://api.hxxfb.com/taobao_service/baichuan.html
42
+TB.AUTH_REDIRECT_URI: https://api.hxxfb.com/taobao_service/baichuan.html
43
+
44
+TB.AUTH_ERROR_REDIRECT_URI: https://api.hxxfb.com/taobao_service/auth_error.html

+ 1 - 1
thirdPartyWares_service/src/main/resources/application.yml

@@ -2,7 +2,7 @@ spring:
2 2
   application:
3 3
     name: thirdPartyWares-service
4 4
   profiles:
5
-    active: dev
5
+    active: pro
6 6
   cache:
7 7
     type: caffeine
8 8
     caffeine:

+ 229 - 0
thirdPartyWares_service/src/main/resources/static/auth_error.html

@@ -0,0 +1,229 @@
1
+<!DOCTYPE html>
2
+<html lang="zh-CN">
3
+
4
+<head>
5
+    <meta charset="UTF-8" />
6
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+    <title>内容展示</title>
8
+    <style>
9
+        /* 保留你原有的样式结构,这里可自定义 */
10
+        * {
11
+            margin: 0;
12
+            padding: 0;
13
+            box-sizing: border-box;
14
+        }
15
+
16
+        body {
17
+            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
18
+            background: linear-gradient(135deg, #ff5000 0%, #ff7a45 100%);
19
+            min-height: 100vh;
20
+            display: flex;
21
+            align-items: center;
22
+            justify-content: center;
23
+            padding: 20px;
24
+        }
25
+
26
+        .container {
27
+            background: white;
28
+            border-radius: 20px;
29
+            box-shadow: 0 20px 40px rgba(255, 80, 0, 0.2);
30
+            padding: 40px 30px;
31
+            text-align: center;
32
+            max-width: 90%;
33
+            width: 350px;
34
+            animation: fadeIn 0.5s ease-out;
35
+        }
36
+
37
+        @keyframes fadeIn {
38
+            from {
39
+                opacity: 0;
40
+                transform: translateY(20px);
41
+            }
42
+
43
+            to {
44
+                opacity: 1;
45
+                transform: translateY(0);
46
+            }
47
+        }
48
+
49
+        .success-icon {
50
+            width: 80px;
51
+            height: 80px;
52
+            background: linear-gradient(135deg, #ff5000 0%, #ff7a45 100%);
53
+            border-radius: 50%;
54
+            display: flex;
55
+            align-items: center;
56
+            justify-content: center;
57
+            margin: 0 auto 20px;
58
+        }
59
+
60
+        .success-icon::after {
61
+            content: "✓";
62
+            color: white;
63
+            font-size: 40px;
64
+            font-weight: bold;
65
+        }
66
+
67
+        h1 {
68
+            color: #333;
69
+            font-size: 24px;
70
+            margin-bottom: 10px;
71
+        }
72
+
73
+        p {
74
+            color: #666;
75
+            font-size: 16px;
76
+            line-height: 1.5;
77
+            margin-bottom: 25px;
78
+        }
79
+
80
+        .taokouling-box {
81
+            background: #fff9f5;
82
+            border: 1px solid #ffebe1;
83
+            border-radius: 12px;
84
+            padding: 15px;
85
+            margin: 25px 0;
86
+            position: relative;
87
+        }
88
+
89
+        .taokouling-text {
90
+            font-size: 18px;
91
+            font-weight: bold;
92
+            color: #ff5000;
93
+            word-break: break-all;
94
+            user-select: all;
95
+        }
96
+
97
+        .copy-btn {
98
+            background: linear-gradient(135deg, #ff5000 0%, #ff7a45 100%);
99
+            color: white;
100
+            border: none;
101
+            border-radius: 50px;
102
+            padding: 15px 25px;
103
+            font-size: 16px;
104
+            font-weight: bold;
105
+            cursor: pointer;
106
+            width: 100%;
107
+            transition: all 0.3s ease;
108
+            margin-top: 10px;
109
+            box-shadow: 0 4px 15px rgba(255, 80, 0, 0.3);
110
+        }
111
+
112
+        .copy-btn:hover {
113
+            transform: translateY(-2px);
114
+            box-shadow: 0 10px 20px rgba(255, 80, 0, 0.4);
115
+        }
116
+
117
+        .copy-btn:active {
118
+            transform: translateY(0);
119
+        }
120
+
121
+        .loading {
122
+            display: none;
123
+            margin: 20px auto;
124
+        }
125
+
126
+        .spinner {
127
+            border: 3px solid #ffebe1;
128
+            border-top: 3px solid #ff5000;
129
+            border-radius: 50%;
130
+            width: 30px;
131
+            height: 30px;
132
+            animation: spin 1s linear infinite;
133
+            margin: 0 auto;
134
+        }
135
+
136
+        @keyframes spin {
137
+            0% {
138
+                transform: rotate(0deg);
139
+            }
140
+
141
+            100% {
142
+                transform: rotate(360deg);
143
+            }
144
+        }
145
+
146
+        .message {
147
+            margin-top: 15px;
148
+            padding: 10px;
149
+            border-radius: 8px;
150
+            font-size: 14px;
151
+            display: none;
152
+        }
153
+
154
+        .success-message {
155
+            background-color: #fff5e6;
156
+            color: #cc4100;
157
+            border: 1px solid #ffd0b3;
158
+        }
159
+
160
+        .error-message {
161
+            background-color: #ffece6;
162
+            color: #cc3200;
163
+            border: 1px solid #ffb3a0;
164
+        }
165
+
166
+        .redirect-info {
167
+            font-size: 14px;
168
+            color: #ff9c66;
169
+            margin-top: 20px;
170
+        }
171
+
172
+        body {
173
+            margin: 0;
174
+            padding: 20px;
175
+            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
176
+            background-color: #f5f5f5;
177
+            color: #333;
178
+        }
179
+
180
+        .content-container {
181
+            background: #fff;
182
+            border-radius: 12px;
183
+            padding: 30px;
184
+            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
185
+            word-break: break-word;
186
+            white-space: pre-wrap;
187
+            /* 保留换行和空格 */
188
+        }
189
+
190
+        .empty-tip {
191
+            color: #999;
192
+            text-align: center;
193
+            font-style: italic;
194
+        }
195
+    </style>
196
+</head>
197
+
198
+<body>
199
+    <div class="content-container">
200
+        <div id="content-display" class="empty-tip">加载中...</div>
201
+    </div>
202
+
203
+    <script>
204
+        // 从 URL 查询参数中获取 content 字段
205
+        function getUrlParam(name) {
206
+            const urlParams = new URLSearchParams(window.location.search);
207
+            return urlParams.get(name);
208
+        }
209
+
210
+        // 获取 content 参数
211
+        const content = getUrlParam('msg');
212
+
213
+        // 解码(如果 content 是 encodeURIComponent 编码过的)
214
+        const decodedContent = content ? decodeURIComponent(content) : null;
215
+
216
+        // 显示内容
217
+        const displayEl = document.getElementById('content-display');
218
+        if (decodedContent) {
219
+            // 注意:如果 content 包含 HTML 标签且你信任来源,可用 innerHTML
220
+            // 否则建议用 textContent 防止 XSS
221
+            displayEl.textContent = decodedContent;
222
+            displayEl.classList.remove('empty-tip');
223
+        } else {
224
+            displayEl.textContent = '未提供 content 参数';
225
+        }
226
+    </script>
227
+</body>
228
+
229
+</html>