fix(hjc): 短信验证码发送成功却报「服务暂不可用」——data 不是对象时解析就炸
CoreResult.of 用 json.getJSONObject("data") 取 data。fastjson 见到 String 值会
当成 JSON 再解析一次,而核心实例 ApiResult.data 是 Object,/sendSmsCaptcha 成功
时给的就是阿里云返回的字符串 "OK"(core 的 MainController 是
success("发送成功", result.get("Message"))),解析 "OK" 抛 JSONException。
该异常发生在 of() 内部,不在那个只包住 parseObject(raw) 的 try 里,于是逃到
execute() 的兜底 catch,被改写成 code=-1「认证服务暂不可用,请稍后重试」。
实际后果是短信已经发出去了,用户和前端看到的却是发送失败:核心实例侧验证码已
写入 Redis、60 秒重发限制与当日 10 条计数均已消耗,用户一重试就撞上
「发送过于频繁」,看起来更像坏了。login/register/captcha 的 data 都是对象,
所以只有发送短信这一条路坏。
- data 改为只接受对象,取不到即 null,绝不抛异常(toObjectData 保留 Map 分支,
兼容 fastjson 桥接层给出的普通 Map);调用方本就只按 code 判成败,明细读 raw
- 新增 HjcCoreAuthClientResultTest:用日志里的真实响应体走完整调用链
(sendSmsCaptcha → post → execute → of,只打桩 doExecute 出口)。
改前该用例复现出逐字相同的异常(栈同在 of(HjcCoreAuthClient.java:93)),改后绿
- 用例同时锁住:data 为对象(登录/验证码)、业务失败无 data 键、data 为数字/数组、
响应根本不是 JSON(网关 HTML)四种情形
- application.yml:hjc.one-stop.base-url 由空串改为 http://180.141.88.21:8810
(base-url 为空时一站式推送不会发起,此前上线一直缺这项配置)
- 未改动核心实例代码,改动面限于 hjc 包与上述配置
This commit is contained in:
@@ -10,6 +10,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 汇吉采登录认证对核心实例的调用出口。
|
||||
@@ -64,7 +65,7 @@ public class HjcCoreAuthClient {
|
||||
private int code;
|
||||
private String message;
|
||||
private String error;
|
||||
/** 成功时的 data(核心实例的 LoginResult / CaptchaResult) */
|
||||
/** 成功时的 data(核心实例的 LoginResult / CaptchaResult);不是对象时留空,明细看 {@link #raw} */
|
||||
private JSONObject data;
|
||||
/** 原始响应体,仅用于日志与异常排查 */
|
||||
private String raw;
|
||||
@@ -90,10 +91,33 @@ public class HjcCoreAuthClient {
|
||||
r.code = json.getIntValue("code");
|
||||
r.message = json.getString("message");
|
||||
r.error = json.getString("error");
|
||||
r.data = json.getJSONObject("data");
|
||||
r.data = toObjectData(json.get("data"));
|
||||
r.ok = r.code == 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* 把 {@code data} 取成 JSONObject,<b>取不到就是 null,绝不抛异常</b>。
|
||||
*
|
||||
* <p>不能用 {@code json.getJSONObject("data")}:fastjson 见到 String 会当成 JSON 再解析一次,
|
||||
* 而核心实例的 {@code data} 是 {@code Object},{@code /sendSmsCaptcha} 成功时给的就是阿里云的
|
||||
* 字符串 {@code "OK"}(core 里是 {@code success("发送成功", result.get("Message"))})。
|
||||
* 解析 {@code "OK"} 抛的 {@code JSONException} 会一路逃到 {@link #execute} 的兜底 catch,
|
||||
* 被改写成「认证服务暂不可用,请稍后重试」——<b>短信其实已经发出去了,用户却看到发送失败</b>,
|
||||
* 核心实例那侧 60 秒重发限制和当日计数还已经消耗掉了。</p>
|
||||
*
|
||||
* <p>调用方一律按 {@code code} 判成败;{@code data} 不是对象时不需要它的内容,要明细读 {@code raw}。</p>
|
||||
*/
|
||||
private static JSONObject toObjectData(Object value) {
|
||||
if (value instanceof JSONObject) {
|
||||
return (JSONObject) value;
|
||||
}
|
||||
// fastjson 解析出来的嵌套对象可能只是普通 Map(不是 com.alibaba.fastjson.JSONObject 的实例)
|
||||
if (value instanceof Map) {
|
||||
return new JSONObject((Map<String, Object>) value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user