防止数据重复,通过session保存url和请求参数来校验

本文介绍了一个用于防止用户在Web应用中重复提交相同表单数据的拦截器实现。该拦截器通过检查会话中保存的URL和请求参数来判断是否为重复提交。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. package com.thinkgem.jeesite.common.repeat_form_validator;  
  2.   
  3. import java.lang.reflect.Method;  
  4. import java.util.HashMap;  
  5. import java.util.Map;  
  6.   
  7. import javax.servlet.http.HttpServletRequest;  
  8. import javax.servlet.http.HttpServletResponse;  
  9.   
  10. import org.springframework.web.method.HandlerMethod;  
  11. import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;  
  12.   
  13. import com.thinkgem.jeesite.common.mapper.JsonMapper;  
  14.   
  15. /** 
  16.  * 一个用户 相同url 同时提交 相同数据 验证 
  17.  * 主要通过 session中保存到的url 和 请求参数。如果和上次相同,则是重复提交表单 
  18.  * @author Administrator 
  19.  * 
  20.  */  
  21. public class SameUrlDataInterceptor  extends HandlerInterceptorAdapter{  
  22.       
  23.       @Override  
  24.         public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
  25.            if(repeatDataValidator(request))//如果重复相同数据                
  26.         return false;      
  27.   else                        
  28. return true;
  29.   
  30.   }  
  31.     /** 
  32.      * 验证同一个url数据是否相同提交  ,相同返回true 
  33.      * @param httpServletRequest 
  34.      * @return 
  35.      */  
  36.     public boolean repeatDataValidator(HttpServletRequest httpServletRequest)  
  37.     {  
  38.         String params=JsonMapper.toJsonString(httpServletRequest.getParameterMap());  
  39.         String url=httpServletRequest.getRequestURI();    
  40.         Object preUrlParams=httpServletRequest.getSession().getAttribute(url); 
  41.  
  42.         if(preUrlParams==null)//如果上一个数据为null,表示还没有访问页面  
  43.         {  
  44.             httpServletRequest.getSession().setAttribute(url, params);  
  45.             return false;  
  46.         }  
  47.         else//否则,已经访问过页面  
  48.         {  
  49.             if(preUrlParams.toString().equals(params))//如果上次url+数据和本次url+数据相同,则表示重复添加数据  
  50.             {  
  51.                   
  52.                 return true;  
  53.             }  
  54.             else//如果上次 url+数据 和本次url加数据不同,则不是重复提交  
  55.             {  
  56.                 httpServletRequest.getSession().setAttribute(url, params);  
  57.                 return false;  
  58.             }  
  59.               
  60.         }  
  61.     }  
  62.   
  63. }  
<think>我们正在处理一个关于接口请求缺少SESSION参数导致本机控件与服务器版本不一致的问题。根据提供的引用信息,我们可以从Session的管理传递角度来分析问题。引用[1]提到:Session不可跨域,且当客户端关闭浏览器时Session会消失(因为会话级别的Cookie被销毁),但服务器上的Session会等待超时。同时,在重定向(REDIRECT)时需要注意设置endResponse为FALSE以保持Session。引用[4]详细解释了Session的生命周期:SessionID存储在客户端的Cookie中(通常是会话Cookie,关闭浏览器即消失),而Session数据在服务器端存储。当客户端关闭浏览器时,SessionID丢失,但服务器上的Session数据会存在直到过期。如果再次访问,会创建新的Session(新的SessionID),原来的Session数据虽然还在服务器,但因为没有SessionID而无法访问。用户的问题:接口请求缺少SESSION参数,导致本机控件与服务器版本不一致。分析:接口请求缺少SESSION参数,可能是因为在请求接口时,没有正确传递SessionID(可能是Cookie中的SessionID丢失,或者没有在请求中携带)。而“本机控件与服务器版本不一致”可能是由于缺少Session参数导致服务器无法识别客户端的状态(比如之前存储的某些信息),进而认为客户端的状态(如控件的版本)与服务器要求的不一致。解决方案思路:1.确保在接口请求时携带SessionID。通常SessionID是通过Cookie自动携带的,但如果是非浏览器环境(如本机控件)或跨域请求,可能需要手动处理。2.检查Session的传递机制。在浏览器中,同一域下的请求会自动携带Cookie(包括SessionID)。但如果是跨域,则需要处理跨域问题(如设置CORS,并允许携带Cookie)。3.如果是本机控件(如ActiveX、浏览器插件等)发起的请求,可能无法像浏览器那样自动管理Cookie。此时需要手动在请求头中设置SessionID。具体步骤:步骤1:确认SessionID的传递方式-在浏览器中,可以通过开发者工具(Network)查看请求头中是否包含Cookie,其中是否有SessionID(如JSESSIONID、PHPSESSID等)。-如果是本机控件,需要检查控件在发送请求时是否能够获取到SessionID并添加到请求头中。步骤2:解决跨域问题(如果存在)-如果接口请求是跨域的,需要在服务器端设置响应头,允许跨域并允许携带凭证(credentials)。例如:Access-Control-Allow-Origin:具体的域名(不能是*,因为要携带凭证)Access-Control-Allow-Credentials:true-同时,客户端在发起请求时也需要设置withCredentials为true(对于XMLHttpRequest或fetchAPI)。步骤3:确保Session在服务器端正确管理-检查服务器端Session的配置,比如过期时间等。确保在客户端多次请求之间,服务器端的Session没有过期或被销毁。步骤4:处理版本不一致问题-由于缺少Session参数,服务器可能无法识别客户端的状态,因此返回了版本不一致的错误。确保每次请求都携带正确的SessionID,这样服务器就能识别客户端的状态(比如之前存储的控件版本信息)。步骤5:针对本机控件的特殊处理-如果本机控件无法自动管理Cookie,可以考虑以下方式:a.让控件从浏览器中获取当前的SessionID(如果控件在浏览器环境中运行),然后将其添加到每个请求的Cookie头中。b.或者,服务器可以接受将SessionID作为请求参数(例如URL参数)传递,但这通常不安全,不推荐。根据引用[3]中提到的,有时需要每个浏览器窗口有独立的Session。但用户的问题不是这个,而是缺少Session参数。因此,我们不需要设置独立的Session,而是需要确保Session参数被正确传递。总结解决方案:1.确保在请求接口时,请求头中携带了正确的Cookie(包含SessionID)。2.如果是跨域请求,服务器需要设置允许跨域携带凭证,客户端设置withCredentials。3.本机控件需要主动获取并设置SessionID到请求头中(如果无法自动管理Cookie)。注意:如果本机控件是独立的应用程序(非浏览器插件),那么它无法直接使用浏览器的SessionID。这时可能需要通过其他方式(如登录后由服务器返回一个token,然后控件使用这个token进行认证)来维持会话。如果问题仍然存在,可能需要检查服务器端日志,查看具体错误(如引用[2]提到的控制文件版本不一致,可能是服务器端的问题,需要根据具体错误进行恢复)。根据用户的问题,我们主要关注如何解决缺少SESSION参数的问题,因此重点放在确保SessionID的传递上。相关问题:1.如何确保跨域请求中携带SessionID?2.本机控件如何获取浏览器的SessionID?3.服务器端如何配置Session过期时间?4.除了Cookie,还有其他方式传递SessionID吗?</think>### 解决接口请求缺少SESSION参数导致版本不一致问题 #### 问题分析 当接口请求缺少SESSION参数时,会导致服务器无法识别客户端状态(如本机控件版本),从而触发版本不一致错误(如引用[2]的ORA-00214)。核心原因包括: 1. **SESSION传递失败**:跨页面/跨域请求未正确携带SESSION(引用[1]) 2. **客户端状态丢失**:浏览器关闭或新窗口未继承SESSION(引用[3][4]) 3. **控件版本管理机制依赖SESSION**:服务器通过SESSION验证客户端版本 --- #### 解决方案 ##### 1. 确保SESSION正确传递(关键步骤) ```java // 示例:Java中重定向时保留SESSION response.sendRedirect("/targetPage"); // 错误:默认关闭响应流 // 正确做法(设置endResponse=false) request.getRequestDispatcher("/targetPage").forward(request, response); ``` - **原理**:服务器端重定向可保持SESSION(引用[1]) - **跨域场景**:需在响应头添加 `Access-Control-Allow-Credentials: true` 并配合 `withCredentials=true` ##### 2. 客户端绑定SESSION参数 ```javascript // 前端请求显式携带SESSION(如Cookie或Header) fetch("/api/interface", { headers: { "Session-ID": getSessionID() }, // 手动注入SESSION credentials: "include" // 允许携带Cookie }); ``` - **适用场景**:本机控件调用接口时主动注入SESSION ##### 3. 版本校验机制优化 ```sql -- 服务器端增加版本兼容逻辑(以Oracle为例) ALTER SYSTEM SET "_allow_resetlogs_corruption"=TRUE SCOPE=SPFILE; -- 避免因版本校验失败中断请求(引用[2]) ``` ##### 4. 浏览器SESSION隔离配置(引用[3]) - **注册表法**: `HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings` 新建DWORD值 `EnableSessionCookie=0` - **启动参数法**: `iexplore.exe -nomerge` --- #### 根本性预防措施 1. **SESSION持久化** 将会话数据存储到Redis/DB,而非依赖内存(解决SESSION超时问题,引用[4]) 2. **版本协商机制** 接口首次请求返回服务器版本,客户端本地缓存并后续携带 3. **无状态Token验证** 用JWT替代SESSION,在Token中嵌入版本信息: ```json {"client_ver": "1.2.3", "exp": 1690000000} ``` > **关键点**:SESSION超时后服务器数据仍存在但无法访问(引用[4]),因此需要主动管理生命周期而非依赖浏览器行为。 --- #### 相关问题 1. 如何设计跨域接口的SESSION传递机制? 2. 浏览器关闭后如何恢复SESSION状态? 3. 除了SESSION,还有哪些方法实现客户端版本校验? 4. 如何优化Oracle数据库的版本控制文件同步?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值