今天客服人员反馈,线上环境用户收到不到绑定会员的验证码(阿里云短信服务),我脑海中的第一反应是:“操,阿里云账户余额是不是又没钱了”。为什么会这么想呢?因为之前都发生过好几次这样的事情了。再仔细想想,“我前几天不是刚买了短信包吗?应该不会没钱了”。然后我熟练的打开了日志监控平台,看到了让我无法淡定的日志(见下图):
在看下发送短信的代码,简直让我崩溃,这日志打印和不打印有什么区别吗?我就想看下发送短信的结果,咋这么难?(之前开发人员的杰作):
public static SendSmsResponse sendSms(String templateCode, String accessKeyId, String accessKeySecret, String phone,
String signName, String templateParam) {
SendSmsResponse sendSmsResponse = null;
try {
// 设置超时时间-可自行调整
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
// 初始化ascClient,暂时不支持多region(请勿修改)
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
DefaultProfile.addEndpoint("xxxxx", "xxxxx", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
// 组装请求对象
SendSmsRequest request = new SendSmsRequest();
// 使用post提交
request.setMethod(MethodType.POST);
// 必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式;发送国际/港澳台消息时,接收号码格式为00+国际区号+号码,如“0085200000000”
request.setPhoneNumbers(phone);
// 必填:短信签名-可在短信控制台中找到
request.setSignName(signName);
// 必填:短信模板-可在短信控制台中找到,发送国际/港澳台消息时,请使用国际/港澳台短信模版
request.setTemplateCode(templateCode);
// 可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
// 友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败
request.setTemplateParam(templateParam);
// 请求失败这里会抛ClientException异常
sendSmsResponse = acsClient.getAcsResponse(request);
if (sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK")) {
// 请求成功
logger.info("=====sms send success====");
} else {
logger.error("=====sms send fail=======");
}
} catch (ClientException e) {
logger.error("=====sms send fail=======");
logger.error(e.getMessage(), e);
}
return sendSmsResponse;
}
抱怨归抱怨,为了尽快找了短信发送不成功的原因,我想到了老伙伴arthas(经常使用它定位线上问题),使用它可以监控方法的入参和出参,于是我在服务器快速输入了以下命令:
# 下载arthas(其实服务器早就有这个jar包,这里为了演示使用方法)
curl -O https://arthas.aliyun.com/arthas-boot.jar
# 运行arthas
java -jar arthas-boot.jar
# 输入应用序号,比如1是短信服务
1
# 输入监听方法命令
watch com.yn.netcafe.sms.AliSms sendSms "{params,returnObj}" -x 2
#效果如下
method=com.yn.netcafe.sms.AliSms.sendSms location=AtExit
ts=2021-02-23 12:54:14; [cost=124.243518ms] result=@ArrayList[
@Object[][
@String[短信模板],
@String[accessKeyId],
@String[accessKeySecret],
@String[手机号],
@String[短信签名],
@String[{"code":"899503"}],
],
@SendSmsResponse[
requestId=@String[969AE94E-04E4-466C-8A81-D83CA17B709E],
bizId=null,
code=@String[isv.SMS_SIGNATURE_ILLEGAL],
message=@String[签名不合法(不存在或被拉黑)],
],
]
到了这里,短信发送失败的原因也水落石出了,短信签名有问题(其他同事改了这块逻辑!!!)。说了这么多,其实就想表达arthas真的挺好用的,具体内部原理和使用方法,大家可以参照arthas官网http://arthas.gitee.io