Description or Example
# 逆天大坑
## 无论是否可以获取到验证码, 都显示无法重复获取问题
> 这是因为超时控制, 发送验证码的过程时间比较长, 所以, 一旦超时, feign会重新调用, 因此会导致无论是否能陈工获取显示这个
```yml
ribbon:
# 连接允许存在的最大时间
ReadTimeout: 1000
# 返回资源允许的最大时间
ConnectTimeout: 10000
```
# 源码
```java
@Controller
public class LoginRegisterController {
@Autowired
private SMSService smsService;
@GetMapping("/sms/sendCode")
@ResponseBody
public R getPhoneCode(@RequestParam(value = "phone", required = false) String phone
,@RequestParam(value = "email", required = false) String email) {
// 优先使用邮箱验证码
if (email != null) return smsService.sendSMS(null, email);
return smsService.sendSMS(phone, null);
}
}
```
```java
@FeignClient("bitmall-thirdpart")
public interface SMSService {
@RequestMapping("/thirdpart/sms/sendCode")
R sendSMS(@RequestParam(value = "phone", required = false) String phone
,@RequestParam(value = "email", required = false) String email);
}
```
```java
@RestController
@RequestMapping("thirdpart/sms")
public class SMSController {
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private SMSComponent smsComponent;
/**
* 给指定的手机号发送纯数字验证码
* 这两个参数不可能同时存在
* @param phone 接受验证码的手机号
* @param email 接受验证码的邮箱
* @return
*/
@RequestMapping("/sendCode")
public R sendSMS(@RequestParam(value = "phone", required = false) String phone
,@RequestParam(value = "email", required = false) String email) {
// 1. 获取Redis里面的缓存起来的验证码(做出了判断, 要么就手机验证码, 要么就email)
// 即便同时存在, 优先使用邮箱验证码
String key = email != null ? EMAIL_SMS_CODE + email : PHONE_SMS_CODE + phone;
String code = redisTemplate.opsForValue().get(key);
// 判断验证码是否存在
if (StringUtils.isNotBlank(code)) {
// 继续判断是否超过防刷时限
Long createTimeMillis = Long.valueOf(code.split("_")[1]);
Long curTimeMillis = System.currentTimeMillis();
long minutes = (curTimeMillis - createTimeMillis) / 60000; // 距今多少分钟
// 这里做了一个规定, 三分钟内只能获取一个验证码
if (minutes < 4) {
return R.error(SMS_FAILURE.getCode(), SMS_FAILURE.getMessage());
}
}
// 到这里说明没有获取过验证码或者验证码需要再次获取
// 优先使用邮箱的字符串和数字混合的验证码
code = email != null ? RandomUtil.randomString(6) :RandomUtil.randomNumbers(6);
// 保存到redis
// 过期时间默认是15分钟
redisTemplate.opsForValue().set(key, code + "_" + System.currentTimeMillis(), 15, TimeUnit.MINUTES);
try {
if (email != null) smsComponent.sendEmailCode(email, EMAIL_REGISTER_SUBTITLE, code);
else smsComponent.sendSMS(phone, code);
} catch (ExecutionException | InterruptedException e) {
return R.error(SMS_GET_FAILURE.getCode(), SMS_GET_FAILURE.getMessage());
}
return R.ok();
}
}
```