平安证券股票交易接口,接口幂等性校验
概念
幂等是一个数学与计算机学概念,常见于抽象代数中。
在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。
这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“getUsername()和setTrue()”函数就是一个幂等函数.
幂等性,通俗的说就是一个平安证券股票交易接口,接口,多次发起同一个请求,必须保证操作只能执行一次,比如:
订单平安证券股票交易接口,接口,不能多次创建订单支付平安证券股票交易接口,接口,重复支付同一笔订单只能扣一次钱支付宝回调平安证券股票交易接口,接口,可能会多次回调,必须处理重复回调普通表单提交平安证券股票交易接口,接口,因为网络超时等原因多次点击提交,只能成功一次等等
常见解决方案
唯一索引–防止新增脏数据token机制–防止页面重复提交悲观锁–获取数据的时候加锁(锁表或锁行)乐观锁–基于版本号version实现,在更新数据那一刻校验数据分布式锁–redis(jedis、redisso或zookeeper实现状态机–状态变更,更新数据时判断状态
本文实现方案
本文采用第2种方式实现,即通过redis+token机制实现平安证券股票交易接口,接口幂等性校验
为需要保证幂等性的每一次请求创建一个唯一标识token,先获取token,并将此token存入redis,请求平安证券股票交易接口,接口时,将此token放到header或者作为请求参数请求平安证券股票交易接口,接口,后端平安证券股票交易接口,接口判断redis中是否存在此token,如果存在,正常处理业务逻辑,并从redis中删除此token,那么,如果是重复请求,由于token已被删除,则不能通过校验,返回请勿重复操作提示,如果不存在,说明参数不合法或者是重复请求,返回提示即可
核心代码
依赖库
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.9'
implementation 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
自定义注解
/**
* 在需要保证 平安证券股票交易接口,接口幂等性 的Controller的方法上使用此注解
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiIdempotent {
}
/**
* token业务处理,提供token创建、token验证平安证券股票交易接口,接口
* Created by double on 2019/7/11.
*/
@Service
public class TokenServiceImpl implements TokenService {
private static final String TOKEN_NAME = 'token';
@Autowired
StringRedisTemplate stringRedisTemplate;
@Override
public ServerResponse createToken() {
//通过UUID来生成token
String tokenValue = 'idempotent:token:' + UUID.randomUUID().toString();
//将token放入redis中,设置有效期为60S
stringRedisTemplate.opsForValue().set(tokenValue, '0', 60, TimeUnit.SECONDS);
return ServerResponse.success(tokenValue);
}
/**
* @param request
*/
@Override
public void checkToken(HttpServletRequest request) {
String token = request.getHeader(TOKEN_NAME);
if (StringUtils.isBlank(token)) {
token = request.getParameter(TOKEN_NAME);
if (StringUtils.isBlank(token)) {
//没有携带token,抛异常,这里的异常需要全局捕获
throw new ServiceException(ResponseCode.ILLEGAL_ARGUMENT.getMsg());
}
}
//token不存在,说明token已经被其他请求删除或者是非法的token
if (!stringRedisTemplate.hasKey(token)) {
throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getMsg());
}
boolean del = stringRedisTemplate.delete(token);
if (!del) {
//token删除失败,说明token已经被其他请求删除
throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getMsg());
}
}
}
/**
* 平安证券股票交易接口,接口幂等性校验拦截器
* Created by double on 2019/7/11.
*/
public class IdempotentTokenInterceptor implements HandlerInterceptor {
@Autowired
private TokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
//幂等性校验, 校验通过则放行, 校验失败则抛出异常, 并通过统一异常处理返回友好提示
ApiIdempotent apiIdempotent = handlerMethod.getMethod().getAnnotation(ApiIdempotent.class);
if (apiIdempotent != null) {
tokenService.checkToken(request);
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
测试
测试平安证券股票交易接口,接口Controller
/**
* 幂等性测试平安证券股票交易接口,接口
* Created by double on 2019/7/11.
*/
@RestController
@RequestMapping('/test')
public class TestController {
@Autowired
private TestService testService;
@ApiIdempotent
@PostMapping('testIdempotent')
public ServerResponse testIdempotent() {
return testService.testIdempotence();
}
}
获取token
{
'status': 0,
'msg': 'idempotent:token:80dd47ed-fa63-4b30-82fa-f3ee4fd64a50',
'data': null
}
验证平安证券股票交易接口,接口安全性
http://localhost:8081/test/testIdempotent?token=idempotent:token:b9ae797d-ed1a-4dbc-a94f-b7e45897f0f5
第一次请求
{
'status': 0,
'msg': 'test idempotent success',
'data': null
}
重复请求
{
'status': 1,
'msg': '请勿重复操作',
'data': null
}
利用jmeter测试工具模拟50个并发请求,获取一个新的token作为参数
设置50个线程请求一次
设置请求IP、Path、参数等信息
文章为作者独立观点,不代表股票交易接口观点