当前位置:网站首页>Interface idempotency problem
Interface idempotency problem
2022-07-28 05:44:00 【Little madman green】
How to prevent interface idempotency is often asked in actual projects or interviews , Therefore, summarize the methods I have been exposed to .
1. Use redis Delay interception
Let the front end transmit the necessary information and timestamp, and then store it redis, utilize redis To intercept repeated requests , This method is also the plan I got from several people after I asked them , But this method is proved to be problematic , It is found that repeated transmission will still occur , Therefore, the scheme Not used in the project .
2. Intercept from the business
It refers to a certain period of time or under certain conditions , Only one modification or addition request can be sent , For example, purchasing virtual currency , It is not allowed to purchase before the platform has no currency , This can determine whether to allow repeated operations through state judgment , Or it is only allowed to operate once in a certain time , This can be done through redis The timeout mechanism of + Unique operator id+ Operation type to limit , This scheme is feasible in practical use , Even if there is front-end network jitter, multiple operations , Only one operation will succeed , But it only applies to business scenarios with features .
3. The way of temporary token
For multiple requests caused by front-end or network reasons , We can ask the front end to request a one-time token before requesting the operation interface , When making multiple requests , If the token on the interface is a token , Then only one operation will succeed , This can prevent repeated operation problems caused by multiple triggering requests by the network or the front end , But this way can't deal with ” request token– Request operation interface “ Resending of bundling operation , At present, this method is used in actual projects without the problem of repeated orders .
The following is the scheme code :
/** * Comments against repeated submissions * Put it in Controller class : It indicates that all interfaces of the current class need to consider interface idempotence * On the method : Indicates that the current method needs to consider interface idempotency */
@Target({
ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeatLimiter {
}
Interception of annotations
@Component
@Slf4j
public class TokenInterceptor extends HandlerInterceptorAdapter {
@Value("${jwt.secret}")
private String secret;
@Autowired
private TokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// Get comments on methods
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
PenguinLogThreadLocal.remove();
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("P3P", "CP=CAO PSA OUR");
if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
response.addHeader("Access-Control-Allow-Methods", "POST,GET,TRACE,OPTIONS");
response.addHeader("Access-Control-Allow-Headers", "Content-Type,Origin,Accept");
response.addHeader("Access-Control-Max-Age", "120");
}
if (method.isAnnotationPresent(NoVerificationToken.class)) {
return true;
}
// Verify the legitimacy of users
String token = request.getHeader("token");
response.setContentType("text/javascript;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
Outcome<Long> rspBean = GameTokenUtil.checkToken(token,secret);
PenguinLogThreadLocal.appendLog("tokenResult",rspBean);
if (!rspBean.ok()) {
setOutCome(request,response,rspBean,"401");
return false;
}
UserInfoThreadlocal.put(rspBean.getData());
PenguinLogThreadLocal.setUserId(rspBean.getData().toString());
// Verify the legitimacy of users
rspBean = tokenService.checkUser(UserInfoThreadlocal.get());
if (!rspBean.ok()) {
setOutCome(request,response,rspBean,"401");
return false;
}
// Whether idempotency needs to be considered in verifying the interface
if(method.isAnnotationPresent(RepeatLimiter.class)){
String repeatLimNo = request.getHeader("repeatLimNo");
Outcome<Long> rspReapBean =tokenService.checkRepeatLimNo(repeatLimNo);
if(!rspReapBean.ok()){
setOutCome(request,response,rspReapBean,"402");
return false;
}
}
return true;
}
private PrintWriter setOutCome(HttpServletRequest request,HttpServletResponse response,Outcome<Long> rspBean,String code){
PrintWriter out = null;
try {
JSONObject res = new JSONObject();
res.put("code",new Long(code));
res.put("message",rspBean.getMessage()+"");
res.put("data","");
PenguinLogThreadLocal.setSuccessful(false);
out = response.getWriter();
out.append(res.toString());
return out;
} catch (IOException e) {
log.error(e.getMessage());
}
return out;
}
}
@PostMapping("/repeatLimNo")
@ApiOperation(value = " Get request sequence ", notes = " Get request sequence -- Block duplicate requests ")
public Outcome<String> getToken(@RequestHeader(value = "token") String token, HttpServletRequest request) {
return Outcome.success("", repeatLimiterSeq.generateSeq());
}
token Generate
// Generate Token
@Override
public String generateSeq() {
// Use UUID Generate token
String token = UUID.randomUUID().toString();
token=token.replaceAll("-","");
// Deposit in Redis,key:token, Expiration time 10 minute
redisUtil.set("repeatLimNo::"+token,token,20*60);
PenguinLogThreadLocal.setParam(token);
return token;
}
@Override
public Boolean deleteSeq(String repeatLimNo) {
return stringRedisTemplate.delete("repeatLimNo::"+repeatLimNo);
}
@Override
public String getSeq(String repeatLimNo) {
Object temp=redisUtil.get("repeatLimNo::"+repeatLimNo);
if(temp!=null){
return temp.toString();
}
return null;
}
Back end use code :
@ApiOperation(value = " Test serial number ", notes = " Test serial number ")
@PostMapping(value = " Test serial number ")
@RepeatLimiter
public Outcome testLimiter(@RequestHeader(value = "token") String token, @RequestHeader(value = "repeatLimNo") String repeatLimNo) {
return Outcome.success();
}
边栏推荐
- Openjudge: matrix multiplication
- Example of main diagram of paper model
- Localdatetime removes T, and jsonfield is invalid
- 冶金物理化学复习 -- 金属电沉积过程中的阴极极化,超电势以及阳极和阳极过程
- 标准C语言学习总结9
- Openjudge: count the number of numeric characters
- 图像增强评价指标学习之——结构相似性SSIM
- The essence of dynamic convolution
- GD32F407 移植FreeRTOS+Lwip
- Mabtis(一)框架的基本使用
猜你喜欢

顺序表的增删查改

树莓派WIFI一键连接配置

Review of metallurgical physical chemistry -- Fundamentals of chemical reaction kinetics

Centos7 install MySQL 5.7

链表实现增删查改

Advanced multi threading: the underlying principle of synchronized, the process of lock optimization and lock upgrade

Review of Metallurgical Physical Chemistry - gas liquid phase reaction kinetics

ResNet结构对比

分支与循环语句

How Visio accurately controls the size, position and angle of graphics
随机推荐
冶金物理化学复习 --- 液 - 液相反应动力学
[idea plug-in artifact] teaches you how to set all attributes in an entity class with one click of idea
Openjudge: perpetual calendar
Using Navicat or PLSQL to export CSV format, more than 15 digits will become 000 (e+19) later
wangeditor(@4.7.15)-轻量级的富文本编辑器
图像增强——MSRCR
GD32F407 移植FreeRTOS+Lwip
js数据类型检测与修改检测
蒸馏模型图
You must configure either the server or JDBC driver (via the ‘serverTimezone)
Review of metallurgical physical chemistry ---- gas solid reaction kinetics
C语言回顾(可变参数篇)
The way of deep learning thermodynamic diagram visualization
链表实现增删查改
顺序表的增删查改
RESNET structure comparison
对极大似然估计、梯度下降、线性回归、逻辑回归的理解
Openjudge: filter extra spaces
标准C语言学习总结9
图像增强评价指标学习之——结构相似性SSIM