当前位置: 首页> 科技> 互联网 > dw网页设计软件的学习网站_网站页面排名优化_百度网站大全_成都搜索优化整站优化

dw网页设计软件的学习网站_网站页面排名优化_百度网站大全_成都搜索优化整站优化

时间:2025/7/11 18:20:06来源:https://blog.csdn.net/qq_30294911/article/details/146489340 浏览次数:0次
dw网页设计软件的学习网站_网站页面排名优化_百度网站大全_成都搜索优化整站优化

目录

引言

方案一:前端防护策略

方案二:后端协同控制

方案三:流量控制与过滤

滑动窗口限流

布隆过滤器

方案四:基于框架的实践方案

多层防护策略与最佳实践

总结        


引言

        在Web应用开发中,防止用户重复点击提交是一个常见却棘手的问题。重复提交不仅会导致数据重复、资源浪费,在交易、下单等场景中甚至可能造成严重的业务异常。通常情况下,我们会使用Redis分布式锁来解决这个问题,但当Redis不可用或由于架构限制无法使用时,我们需要其他可靠的替代方案。
        本文将深入探讨几种不依赖Redis的防重复点击方案,从前端到后端,从简单到复杂,分析各自的实现原理、适用场景以及优缺点,帮助开发者根据自身业务需求选择最合适的解决方案。

方案一:前端防护策略

        最直接的防重复点击方案是在前端实现按钮防抖。当用户点击按钮后,立即将按钮禁用或置灰,防止用户进行二次点击。

// 伪代码:防抖按钮实现示例
function debounceButton(btn, time = 2000) {if (btn.disabled) return;// 禁用按钮btn.disabled = true;btn.classList.add('disabled');// 发送请求sendRequest().finally(() => {// 请求完成后恢复按钮状态(也可以根据业务需要不恢复)setTimeout(() => {btn.disabled = false;btn.classList.remove('disabled');}, time);});
}

优点:

  • 实现简单,无需后端配合
  • 用户体验友好,提供直观的视觉反馈
  • 适用于大多数普通业务场景

局限性:

  • 网络延迟可能导致禁用不及时
  • 技术熟练的用户可通过浏览器开发工具绕过前端限制
  • 无法防止通过接口工具(如Postman)直接调用API的重复请求

开发经验分享:在实际项目中,我发现单纯依赖前端防抖虽然能解决80%的问题,但在支付等关键业务中,仍需结合后端验证机制,构建多层防护。

 

方案二:后端协同控制

        Token机制是一种有效的服务端防重复提交方案。核心思想是为每次操作生成唯一标识,确保同一标识只被处理一次。
工作流程:

  1. 用户访问页面时,后端生成唯一token并返回前端
  2. 用户提交请求时携带该token
  3. 后端验证token是否已被使用,未使用则标记为已使用并处理请求
  4. 如token已使用,拒绝请求并返回错误提示

 后端实现示例:

// 伪代码
@RestController
public class OrderController {private final Map<String, Boolean> tokenMap = new ConcurrentHashMap<>();// 获取token@GetMapping("/getToken")public Result getToken() {String token = UUID.randomUUID().toString();tokenMap.put(token, false); // false表示未使用return Result.success(token);}// 提交订单@PostMapping("/submitOrder")public Result submitOrder(@RequestParam String token, @RequestBody OrderDTO order) {// 使用数据库事务保证原子性return transactionTemplate.execute(status -> {// 查询token使用状态Boolean used = tokenMap.get(token);if (used == null) {return Result.error("无效的token");}if (used) {return Result.error("请勿重复提交");}// 标记token为已使用tokenMap.put(token, true);// 处理订单逻辑orderService.createOrder(order);return Result.success();});}
}

数据库实现方案:
        在实际生产环境中,可使用数据库存储token状态,结合事务确保原子性:

-- 创建token表
CREATE TABLE submission_token (token VARCHAR(36) PRIMARY KEY,used BOOLEAN DEFAULT FALSE,create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,expire_time TIMESTAMP
);-- 验证并标记token (使用悲观锁)
BEGIN TRANSACTION;
SELECT used FROM submission_token WHERE token = ? FOR UPDATE;
-- 如果未使用,则标记为已使用
UPDATE submission_token SET used = TRUE WHERE token = ?;
COMMIT;

优点:

  • 服务端验证,安全性高
  • 可靠性强,能防止各种渠道的重复请求
  • 结合数据库事务,保证操作原子性

局限性:

  • 实现复杂度较高
  • 需要额外的存储空间管理token
  • 不适合所有场景下的性能要求

方案三:流量控制与过滤

滑动窗口限流

        滑动窗口限流是控制请求频率的有效方法,可以限制用户在指定时间窗口内的请求次数,从而防止重复提交。

直通车:高并发系统中的限流策略:滑动窗口限流与Redis实现-CSDN博客

 

//伪代码
public class SlidingWindowRateLimiter {// 用户请求记录: <用户ID, 请求时间列表>private Map<String, LinkedList<Long>> requestRecords = new ConcurrentHashMap<>();// 窗口大小(毫秒)private final long windowSize;// 窗口内允许的最大请求数private final int maxRequests;public SlidingWindowRateLimiter(long windowSize, int maxRequests) {this.windowSize = windowSize;this.maxRequests = maxRequests;}/*** 判断请求是否被允许* @param userId 用户ID* @return 是否允许请求*/public synchronized boolean allowRequest(String userId) {long currentTime = System.currentTimeMillis();// 获取用户的请求记录,如不存在则创建LinkedList<Long> records = requestRecords.computeIfAbsent(userId, k -> new LinkedList<>());// 移除窗口外的过期记录while (!records.isEmpty() && currentTime - records.getFirst() > windowSize) {records.removeFirst();}// 判断窗口内请求是否超过限制if (records.size() < maxRequests) {// 记录新请求records.addLast(currentTime);return true;}return false;}
}

使用示例:

// 创建限流器: 2秒内最多允许1次请求
SlidingWindowRateLimiter limiter = new SlidingWindowRateLimiter(2000, 1);@PostMapping("/api/submit")
public Result submit(@RequestHeader String userId) {// 检查限流if (!limiter.allowRequest(userId)) {return Result.error("请求过于频繁,请稍后再试");}// 处理正常业务逻辑return businessService.process();
}

适用场景:

  • 适用于高频操作的防重复控制
  • 对性能要求较高的场景
  • 允许在短时间内丢弃部分请求的业务

布隆过滤器

        布隆过滤器是一个空间效率很高的概率型数据结构,用于判断一个元素是否存在于集合中。它可以快速进行"可能存在"或"一定不存在"的判断,适合作为防重复提交的快速过滤层。

直通车:布隆过滤器原理介绍和典型应用案例_布隆过滤器案例-CSDN博客

// 伪代码
public class BloomFilterValidator {private BitSet bitSet;private int size;private int hashFunctions;public BloomFilterValidator(int size, int hashFunctions) {this.size = size;this.hashFunctions = hashFunctions;this.bitSet = new BitSet(size);}// 添加元素public void add(String element) {for (int i = 0; i < hashFunctions; i++) {int hash = getHash(element, i);bitSet.set(hash);}}// 判断元素是否可能存在public boolean mightContain(String element) {for (int i = 0; i < hashFunctions; i++) {int hash = getHash(element, i);if (!bitSet.get(hash)) {return false; // 一定不存在}}return true; // 可能存在}// 简单哈希函数private int getHash(String element, int seed) {int hash = element.hashCode();hash = hash * seed % size;return Math.abs(hash) % size;}
}

应用架构:

  1. 使用布隆过滤器进行快速判断
  2. 如果过滤器返回"可能存在",则进一步查询数据库确认
  3. 如果确实是重复提交,则拒绝请求
// 伪代码
@Service
public class OrderSubmitService {private BloomFilterValidator bloomFilter = new BloomFilterValidator(10000, 3);private OrderRepository orderRepository;public Result submitOrder(OrderDTO orderDTO) {// 生成请求标识String requestId = generateRequestId(orderDTO);// 布隆过滤器快速检查if (bloomFilter.mightContain(requestId)) {// 可能是重复请求,进一步查询数据库确认if (orderRepository.existsByRequestId(requestId)) {return Result.error("订单已提交,请勿重复操作");}}// 处理订单并保存请求标识Order order = orderService.createOrder(orderDTO);bloomFilter.add(requestId); // 添加到布隆过滤器return Result.success(order);}// 生成请求唯一标识private String generateRequestId(OrderDTO orderDTO) {// 根据关键业务字段生成唯一标识return DigestUtils.md5Hex(orderDTO.getUserId() + orderDTO.getProductId() + orderDTO.getAmount() + System.currentTimeMillis());}
}

优点:

  • 空间效率高,内存占用小
  • 查询速度快,适合大规模数据
  • 作为快速过滤层,降低数据库查询压力

局限性:

  • 有一定的误判率(误报)
  • 不能单独使用,需要与数据库等确切存储配合
  • 不支持删除元素,需要定期重建

方案四:基于框架的实践方案

        参考RuoYi框架的实现,RuoYi框架提供了一种基于表单信息的防重复提交方案,核心思想是将表单内容、提交时间等信息进行校验,限制相同内容在短时间内的重复提交。

/*** 自定义注解防止表单重复提交*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RepeatSubmit {/*** 间隔时间(ms),小于此时间视为重复提交*/int interval() default 5000;
}/*** 防重复提交拦截器*/
@Component
public class RepeatSubmitInterceptor implements HandlerInterceptor {private final FormTokenService tokenService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);if (annotation != null) {// 验证表单是否重复提交return validateFormRepeat(request, annotation);}}return true;}private boolean validateFormRepeat(HttpServletRequest request, RepeatSubmit annotation) {// 获取请求参数内容String formContent = getFormContent(request);// 获取请求路径String requestPath = request.getRequestURI();// 用户标识String userToken = getUserToken(request);// 生成表单唯一标识String formKey = DigestUtils.md5Hex(requestPath + userToken + formContent);// 检查数据库中是否存在且是否在规定时间内FormSubmitRecord record = formRecordRepository.findByFormKey(formKey);if (record != null) {long interval = System.currentTimeMillis() - record.getSubmitTime();if (interval < annotation.interval()) {return false; // 判定为重复提交}}// 记录本次提交saveFormRecord(formKey);return true;}// 获取表单内容private String getFormContent(HttpServletRequest request) {// 获取POST内容或GET参数,进行排序和标准化处理// ...具体实现略}// 保存表单记录private void saveFormRecord(String formKey) {FormSubmitRecord record = new FormSubmitRecord();record.setFormKey(formKey);record.setSubmitTime(System.currentTimeMillis());formRecordRepository.save(record);}
}

使用示例

@RestController
public class UserController {@PostMapping("/user/register")@RepeatSubmit(interval = 10000) // 10秒内不允许重复提交public Result register(@RequestBody UserRegisterForm form) {// 注册逻辑return userService.register(form);}
}

优点:

  • 配置简便,使用注解即可实现
  • 支持配置不同接口的防重复策略
  • 基于表单内容校验,更符合业务语义

局限性:

  • 依赖于请求内容,不适用于所有场景
  • 需要存储请求内容的哈希值
  • 配置不当可能影响用户体验

多层防护策略与最佳实践

        在实际项目中,往往需要综合使用多种防重复点击方案,构建多层防护机制。

前端第一道防线:

  • 实现按钮防抖和禁用
  • 合理设置UI反馈,提升用户体验

API网关层:

  • 实现基本的流量控制和限流
  • 对异常请求进行预警和拦截

应用服务层:

  • 实现token验证或表单校验机制
  • 使用布隆过滤器进行快速过滤

数据持久层:

  • 利用数据库约束和事务保证数据一致性
  • 实现业务层面的幂等性检查

总结        

        ​​​​​​​防止重复点击是一个需要从多角度综合考虑的问题。虽然Redis分布式锁提供了一种优雅的解决方案,但在Redis不可用的场景下,我们仍有多种替代方案可以选择。
        理想的防重复点击方案应当在安全性、可靠性和性能之间找到平衡点。在实际应用中,应根据业务特点、技术栈和性能要求等因素,选择合适的方案或组合方案。同时,也应当注意用户体验,避免过度限制影响正常操作。

关键字:dw网页设计软件的学习网站_网站页面排名优化_百度网站大全_成都搜索优化整站优化

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: