java并发访问重复请求过滤问题

Java并发访问重复请求过滤是一个常见的问题。在高并发场景下,由于网络延迟、异步任务执行时间过长等原因,客户端容易发起重复请求,导致服务端资源浪费或数据异常。因此,需要一种机制来过滤掉重复请求。

一、方案选择

解决这个问题的方案有很多,这里介绍两种比较常见的方案:

  1. 使用Token机制

Token机制的原理是:客户端发送一个请求时,服务端在响应中返回一个Token(如UUID),客户端在下次发送请求时,将Token携带在请求头中,服务端在处理请求时,如果发现Token已被使用过,则认为是重复请求,直接返回之前处理的结果;否则,将Token保存在服务端缓存中,等待客户端下次请求时进行校验。

  1. 使用Set集合

Set集合的原理是:服务端在处理每个请求时,将请求的关键信息(如请求URL、参数等)作为唯一标识,添加到Set集合中;当下次有相同关键信息的请求到来时,直接过滤掉。

二、实现示例

下面通过示例代码演示以上两种方案的实现:

  1. 使用Token机制

public class TokenFilter {
    private static final String TOKEN_KEY = "TOKEN";

    public static boolean isTokenValid(String token) {
        if (StringUtils.isEmpty(token)) {
            return false;
        }
        if (cache.getIfPresent(token) != null) {
            return false;
        }
        cache.put(token, true);
        return true;
    }

    public static void removeToken(String token) {
        cache.invalidate(token);
    }

    // 使用guava的Cache作为缓存
    private static final Cache<String, Boolean> cache = CacheBuilder.newBuilder()
            .maximumSize(10000)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .build();

    public static String getTokenHeader() {
        return TOKEN_KEY + ":" + UUID.randomUUID().toString();
    }
}

TokenFilter中的isTokenValid方法用于校验Token是否有效,removeToken方法用于清除Token。使用了Guava中的Cache集合作为缓存。

在Servlet中,可以这样使用TokenFilter:


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String token = req.getHeader(TokenFilter.TOKEN_KEY);
        if (!TokenFilter.isTokenValid(token)) {
            resp.getWriter().println("重复请求");
            return;
        }

        // 处理请求

        TokenFilter.removeToken(token);
    }

在HTTP响应头中返回Token:


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String token = TokenFilter.getTokenHeader();
        resp.setHeader(TokenFilter.TOKEN_KEY, token);

        // 处理请求
    }

  1. 使用Set集合

public class RequestFilter {
    private static final Set<String> requestInfoSet = Collections.synchronizedSet(new HashSet<>());

    public static boolean isDuplicateRequest(HttpServletRequest request) {
        String requestInfo = getRequestInfo(request);
        if (StringUtils.isEmpty(requestInfo)) {
            return false;
        }
        // 加锁保证原子性
        synchronized (requestInfoSet) {
            if (requestInfoSet.contains(requestInfo)) {
                return true;
            }
            requestInfoSet.add(requestInfo);
            return false;
        }
    }

    private static String getRequestInfo(HttpServletRequest request) {
        String url = request.getRequestURI();
        String queryString = request.getQueryString();
        String method = request.getMethod();
        if (StringUtils.isEmpty(url) || StringUtils.isEmpty(method)) {
            return null;
        }
        if (queryString != null) {
            url += "?" + queryString;
        }
        return url + ":" + method;
    }

    public static void clear() {
        requestInfoSet.clear();
    }
}

RequestFilter中的isDuplicateRequest方法使用了一个Set集合来保存已处理请求的关键信息,synchronizedSet保证了线程安全。getRequestInfo方法将请求URL和方法作为关键信息保存。

在Servlet中,可以这样使用RequestFilter:


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (RequestFilter.isDuplicateRequest(req)) {
            resp.getWriter().println("重复请求");
            return;
        }

        // 处理请求

        RequestFilter.clear();
    }

注意,在处理请求后需要清空requestInfoSet,否则会导致后续请求无法通过检查。

三、总结

两种方案各有优缺点,Token机制需要服务端缓存来保存Token,增加了服务端的负担;Set集合方案简单,但需要注意清空集合。使用哪种方案具体要根据需求选择。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java并发访问重复请求过滤问题 - Python技术站

(0)
上一篇 2023年5月16日
下一篇 2023年5月16日

相关文章

  • 浅谈Java并发中的内存模型

    浅谈Java并发中的内存模型 在Java并发编程中,了解Java内存模型(Java Memory Model,简称JMM)是非常必要的。因为JMM规定了不同线程之间访问共享变量的规则,影响了程序在并发执行时的正确性和性能。下面我们就来详细讲解一下Java并发中的内存模型。 Java内存模型简介 Java内存模型是在JDK 1.2中引入的,它描述了Java虚拟…

    多线程 2023年5月16日
    00
  • Java并发之synchronized实现原理深入理解

    Java并发之synchronized实现原理深入理解 概述 Java中,synchronized关键字是实现多线程同步的一种重要机制,可以让代码块以原子性、独占性执行。在并发编程中,对synchronized的理解非常重要。本文将深入讲解synchronized的实现原理,包括synchronized的底层实现、锁升级机制等方面。 synchronized…

    多线程 2023年5月16日
    00
  • JavaScript多线程的实现方法

    JavaScript 是单线程的语言,这意味着整个程序只有一个执行线程,即只有一个代码段可以被执行。但是,为了提高性能和用户体验,有时候我们需要实现多任务并行执行,此时需要使用 JavaScript 中的多线程技术。 JavaScript 中实现多线程可以通过以下两种方法: Web Workers Web Workers(网络工作者)是一种运行在后台的 Ja…

    多线程 2023年5月17日
    00
  • .NET Windows 多线程thread编程

    针对“.NET Windows 多线程thread编程”,我可以为您提供以下完整攻略: 理解多线程Thread 多线程指的是在同一个进程中,同时存在多个线程(Thread),每个线程去执行一段独立的代码,从而实现多任务并发执行的效果。在Windows应用程序中,多线程编程相对于单线程编程,可以提高应用程序的性能和响应速度,尤其在一些对时间有较高要求的应用中,…

    多线程 2023年5月17日
    00
  • PHP实现Redis单据锁以及防止并发重复写入

    让我为大家详细分享一下关于“PHP实现Redis单据锁以及防止并发重复写入”的攻略。以下是完整的步骤说明: 一、什么是Redis单据锁以及并发重复写入的问题 当多个用户同时操作我们的系统时,可能会发生并发写入的问题。这种情况下,如果没有进行锁机制的控制,可能会导致多个用户同时写入相同的数据,进而导致数据错误和数据丢失的问题。 在这种情况下,我们可以通过使用R…

    多线程 2023年5月16日
    00
  • Java面试题冲刺第二十五天–并发编程2

    下面我将详细讲解“Java面试题冲刺第二十五天–并发编程2”的完整攻略。 标题 Java面试题冲刺第二十五天–并发编程2 内容 介绍 本次攻略主要是针对Java并发编程中的一些问题进行剖析和解决,主要涉及到以下几个方面: 线程池的使用 死锁的排查和解决 并发编程的常见问题和解决方法 线程池的使用 线程池是Java并发编程中非常重要的概念,通过线程池,我们…

    多线程 2023年5月17日
    00
  • 从并发到并行解析Go语言中的sync.WaitGroup

    从并发到并行解析Go语言中的sync.WaitGroup是一篇介绍Go语言中并发编程工具的文章。在该篇文章中,我们会深入了解到什么是并发和并行,以及如何使用sync.WaitGroup来协调并发和并行工作。 并发和并行的定义 并发是指同时执行多个代码段,但并不保证这些代码段的执行顺序。一个被操作系统调度器管理的Go程序就是一个并发程序。 并行是指同时执行多个…

    多线程 2023年5月16日
    00
  • 彻底搞懂Java多线程(四)

    我来详细讲解一下“彻底搞懂Java多线程(四)”的完整攻略。 标题 彻底搞懂Java多线程(四) 具体内容 Java多线程中的一个重要概念就是线程池,线程池可以有效地管理线程的数量,防止资源被浪费,提高程序的性能。本篇文章将详解Java中的线程池。 线程池实现原理 Java中的线程池由Executor框架提供。Executor框架定义了ThreadPoolE…

    多线程 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部