一种网关(服务端)防止重复提交的机制

当前市面上解决重复提交的技术方案主要有以下几种:

  1. 通过JavaScript限制表单重复提交

通过js代码,当用户点击提交按钮后,屏蔽提交按钮或者将重复点击在指定情况下置为无效,使用户无法点击提交按钮或点击无效,从而实现防止表单重复提交。

  1. 给数据库加唯一索引约束

在数据库建表的时候在ID字段添加主键约束,用户名、邮箱、电话等字段加唯一性约束。确保数据库只可以添加一条数据。

  1. 利用session进行防止表单重复提交

服务器返回表单页面时,会先生成一个subToken保存于session,并把该subToen传给表单页面。当表单提交时会带上subToken,服务器拦截器Interceptor会拦截该请求,拦截器判断session保存的subToken和表单提交subToken是否一致。若不一致或session的subToken为空或表单未携带subToken则不通过。

首次提交表单时session的subToken与表单携带的subToken一致走正常流程,然后拦截器内会删除session保存的subToken。当再次提交表单时由于session的subToken为空则不通过。从而实现了防止表单重复提交。

  1. 利用AOP标记重复提交表单信息,自定义不可重复提交时间

    自定义重复提交注解,每次提交表单时Aspect会保存当前标记到redis,并对该缓存设置过期时间,当表单在该缓存过期之前提交则会被认为是重复提交

本方案着重解决无法完全拦截、增加数据库压力、老接口改动成本大、校验时间不灵活等问题,参考方案4,对利用AOP标记重复提交表单方案的基础上进行了优化处理,可以做到以注解的形式应用到所有需要防止表单的接口上,技术实现更轻量级,防重时间把控上随不同接口的响应速度而改变并且有效的减小了服务端与数据库的压力。并且在实际应用中起到了很好的效果。

1、利用AOP技术建立切面,自定义注解;

2、在注解实现中获取用户的所有请求参数与用户信息并按照一定规则对请求参数与用户信息进行排序并舍弃掉参数值为null的参数,以保证每次相同的提交请求进来的参数顺序都是相同的

3、对排序的参数进行一个拼接得到一个拼接的字符串,为了数据的安全性我们在此字符串的基础上加一个自定义的盐(java 盐),此时我们将加盐后得到字符串进行一个hash算法将此字符串处理成一个固定长度的字符串作为防重标识

4、以一个特定的字符串前缀加上第3步我们得到的防重标识作为一个redis的key,目的是日后便于维护查找所有防重复提交的key

5、对redis进行一个incr(key)原子操作得到一个结果锁lock,以保证此方案可以不被并发场景所影响

6、当lock等于1时表示此去请求为正常请求,可以继续往下进行,否则表示当前请求为重复提交请求。

7、当请求为正常请求时再针对该key设置一个托底过期时间,此时间只有在释放lock失败的场景下,此托底时间生效,当托底时间过期之后,redis会因为key过期而自动释放lock以避免该表单被永久锁住永远不可再次提交的情况

8、释放程序正常执行对应接口的逻辑操作并对该释放操作进行try与finally操作,在finally中对redis进行del(key)操作删除此缓存用以释放锁。同时对释放操作进行异常捕捉打印日志,做到出现问题时程序员第一时间知晓问题。此时接口执行完毕之后,自动释放防重复提交锁,下一次提交便可以正常进行。

且看伪代码:

@Around("antiDuplicationAccess()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
   RequestAttributes ra = RequestContextHolder.getRequestAttributes();
   ServletRequestAttributes sra = (ServletRequestAttributes) ra;
   HttpServletRequest request = sra.getRequest();
   Map<String, String> paramsMap = getRequestParams(request);
   String uid = request.getHeader("uid");
   paramsMap.put("uid",uid);
   String sign = JceSecretUtil.hash(SignUtil.sort(paramsMap) + ApiConsts.SIGN_SALT, JceSecretUtil.HashTypeEnum.MD5.getValue());
   if (StringUtils.isBlank(sign)) {
      return pjp.proceed();
   }
   String curSign = ApiConsts.ANTI_DUPLICATION + sign;
   try{
      // 防重复提交
      long lock = Redis.incr(curSign);
      if (lock > 1) {
         //重复提交自定义处理方式,可抛异常
      }
      Redis.expire(curSign, ApiConsts.SIGN_KEY_EXPIRE_TIME);
   }catch (JedisException ex){
      logger.error("Redis Exception, incr or expire is Exception, sign:{},message:{}", curSign, ex);
   }
   try {
      return pjp.proceed();
   } finally {
      try{
         Redis.del(curSign);
      }catch (JedisException ex){
         logger.error("Redis Exception, del is Exception, sign:{},message:{}", curSign, ex);
      }
   }
}

 

 

 

 

### 回答1: OPC DA网关服务端源码是指一种采用OPC技术实现数据采集的软件源代码。OPC是OLE for Process Control的缩写,是一种标准化的工业自动化数据交换协议,可以方便地实现数据的采集、处理和应用。 OPC DA网关服务端源码的功能主要是将不同类型的数据源转化为OPC DA数据,供客户端使用。它可以采集各种不同的数据源,如PLC、传感器、仪表等,将它们转换为OPC的格式,供客户端(如SCADA、HMI等)调用和使用。此外,OPC DA网关服务端源码还可以实现数据的缓存、过滤、压缩等功能,提高数据的质量和可靠性。 OPC DA网关服务端源码的设计需要考虑多种因素,如数据源的类型、网络通信的方式、数据传输的速度、数据处理的功能等。通常,它采用C++等编程语言实现,使用一些常用的开源库和框架来实现数据采集和处理。此外,OPC DA网关服务端源码通常需要进行测试和调试,确保数据的正确性和稳定性。 总之,OPC DA网关服务端源码是一种实现数据采集和处理的软件源代码,能够将不同类型的数据源转换为OPC DA格式,供客户端使用。它设计需要考虑多种因素,并经过测试和调试来确保其稳定性和正确性。 ### 回答2: OPC DA网关服务端源码是一种技术方案,它可用于建立OPC DA兼容系统和SCADA/HMI应用程序之间的通信桥梁。该源码提供了完整的OPC DA规范实现,使应用开发人员可以直接编写通信协议来与OPC DA服务器进行通讯。 源码实现了OPC DA协议服务端的全部功能,并且可以根据实际应用需要进行修改和拓展。使用OPC DA网关服务端源码,可以快速构建一个高性能、稳定可靠的OPC DA服务器,提供通信接口和数据处理能力。 同时,该源码具有源代码开放、可定制化和可扩展性等特点。开发人员可以根据自身需求来进行代码修改和定制,以创造出更加适合特定场景的OPC DA服务器。在实现上,该源码使用C++语言和Visual Studio编译器,同时配备详细的开发文档和示例代码,方便开发人员进行学习和使用。 总的来说,OPC DA网关服务端源码是一种高端的工具,可以构建跨平台通信架构,提高软件开发效率,并为应用开发提供了强有力的支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值