登录
首页 >  文章 >  java教程

Java拦截网络请求,中间件实现全解析

时间:2025-07-24 14:45:08 167浏览 收藏

小伙伴们对文章编程感兴趣吗?是否正在学习相关知识点?如果是,那么本文《如何在Java中拦截网络请求数据 Java实现中间件拦截机制》,就很适合你,本篇文章讲解的知识点主要包括。在之后的文章中也会多多分享相关知识点,希望对大家的知识积累有所帮助!

在Java中拦截网络请求数据的核心方法是使用Spring框架的HandlerInterceptor,它允许在请求处理的不同阶段插入自定义逻辑。1. preHandle方法用于在请求处理前进行权限校验或过滤;2. postHandle方法用于处理完成后、视图渲染前的数据修改;3. afterCompletion方法用于资源清理和异常记录。此外,还可通过Servlet Filter实现更底层的拦截,或使用AOP对方法调用进行细粒度控制。这些机制共同解决了权限控制、日志记录、性能监控、数据清洗、安全防护等横切关注点的问题,使业务代码更简洁清晰。

如何在Java中拦截网络请求数据 Java实现中间件拦截机制

在Java里拦截网络请求数据,说白了,就是要在请求抵达目标处理逻辑(比如一个控制器方法)之前或者之后,插入我们自己的代码逻辑。这通常是通过一种“中间件”或者“切面”的机制来实现的,它允许你在请求处理的生命周期中设置一些“卡点”,做一些额外的处理,比如权限校验、日志记录、性能监控或者数据转换。这并非什么高深莫测的技术,更多的是一种架构设计上的考量。

如何在Java中拦截网络请求数据 Java实现中间件拦截机制

解决方案

要在Java中实现网络请求数据的拦截,尤其是在Web应用背景下,Spring框架的HandlerInterceptor是一个非常优雅且实用的选择。它提供了一套钩子,让你能在请求处理的不同阶段介入。

我们可以定义一个自定义的拦截器,实现HandlerInterceptor接口,并重写其中的方法:

如何在Java中拦截网络请求数据 Java实现中间件拦截机制
  • preHandle(HttpServletRequest request, HttpServletResponse response, Object handler): 在请求被处理前调用。如果你返回false,请求链就会中断,后续的拦截器和处理器方法都不会执行。这非常适合做权限校验、黑名单过滤等。
  • postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView): 在请求被处理后,视图渲染之前调用。你可以在这里修改ModelAndView,或者对响应进行一些通用处理。
  • afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex): 在整个请求处理完成后,视图也渲染完毕之后调用。通常用于资源清理,比如关闭数据库连接、记录异常日志等,即使处理器抛出异常也会执行。

下面是一个简单的HandlerInterceptor实现示例:

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyRequestInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        long startTime = System.currentTimeMillis();
        request.setAttribute("startTime", startTime); // 记录请求开始时间
        System.out.println("请求进入拦截器: " + request.getRequestURI());
        // 假设这里做个简单的权限判断
        String userToken = request.getHeader("X-Auth-Token");
        if (userToken == null || !userToken.equals("valid-token")) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401 未授权
            response.getWriter().write("Unauthorized access!");
            return false; // 阻止请求继续
        }
        return true; // 继续执行后续拦截器和处理器
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("请求处理完成,视图渲染前: " + request.getRequestURI());
        // 可以在这里对返回的ModelAndView做一些修改
        if (modelAndView != null) {
            modelAndView.addObject("appName", "MyWebApp");
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        long startTime = (Long) request.getAttribute("startTime");
        long endTime = System.currentTimeMillis();
        long executeTime = endTime - startTime;
        System.out.println("请求处理结束,总耗时: " + executeTime + "ms for " + request.getRequestURI());
        if (ex != null) {
            System.err.println("请求处理中发生异常: " + ex.getMessage());
        }
    }
}

接着,你需要将这个拦截器注册到Spring MVC的配置中。通常是在实现WebMvcConfigurer接口的配置类里:

如何在Java中拦截网络请求数据 Java实现中间件拦截机制
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyRequestInterceptor())
                .addPathPatterns("/**") // 拦截所有路径
                .excludePathPatterns("/public/**"); // 排除某些路径
    }
}

这样,每次有请求进来,MyRequestInterceptor就会按照定义的规则介入处理。

为什么我们需要拦截网络请求?它能解决什么痛点?

在我看来,拦截网络请求这事儿,核心目的就是为了实现“非侵入性”的通用逻辑处理。你想啊,如果每个控制器方法、每个业务逻辑里都要写一遍权限校验、日志记录、性能统计的代码,那简直是灾难。代码会变得臃肿不堪,维护起来更是噩梦。

它能解决的痛点简直不要太多:

  • 权限与认证: 这是最常见的。用户请求某个资源,我得先知道他有没有这个权限。在preHandle里一判断,没权限直接返回401,根本不用走到后面的业务逻辑,效率高,也安全。
  • 日志记录: 记录每次请求的URL、参数、IP、耗时,甚至响应结果。这对于系统监控、问题排查简直是刚需。在preHandle记录请求信息,在afterCompletion记录响应和耗时,完美。
  • 性能监控: 统计每个接口的响应时间,找出性能瓶颈。这也是在preHandleafterCompletion之间计算时间差就能搞定。
  • 数据转换与清洗: 有时候前端传过来的数据格式不符合后端要求,或者需要统一处理一些特殊字符。在请求到达控制器前进行预处理,或者在响应发出前进行格式化。
  • 安全防护: 比如XSS攻击过滤、CSRF令牌校验等。这些通用的安全检查放在拦截器里做,可以避免每个接口都重复写。
  • 跨域处理: 虽然现在有专门的CORS配置,但在一些老旧或者特定场景下,拦截器也能用来处理CORS相关的HTTP头。
  • 缓存控制: 对某些请求的响应进行缓存,或者根据请求头来判断是否使用缓存。
  • 统一异常处理: 虽然Spring有@ControllerAdvice,但拦截器也能捕获到请求处理过程中的异常,进行统一的记录或响应。

说白了,拦截器就是把那些与核心业务逻辑无关但又必不可少的“横切关注点”剥离出来,集中管理,让我们的业务代码更聚焦,更干净。

除了Spring,还有哪些基础的Java拦截手段?

当然,Spring的HandlerInterceptor虽然好用,但它毕竟是Spring体系下的产物。如果你的项目没有使用Spring,或者你需要更底层、更通用的拦截机制,Java本身也提供了几种方式:

1. Servlet Filter (过滤器)

这是Java Web应用中最基础、最原生的拦截机制。Servlet Filter在请求进入Servlet容器(比如Tomcat)后,但在请求到达任何Servlet(包括Spring MVC的DispatcherServlet)之前就会被执行。它工作在Web应用的更高层面,可以对所有的HTTP请求和响应进行操作。

实现Filter接口,并重写doFilter方法:

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter(urlPatterns = "/*") // 拦截所有路径
public class MyBasicFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("MyBasicFilter 初始化...");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        System.out.println("Filter 拦截到请求: " + httpRequest.getRequestURI());

        // 在这里可以对请求进行预处理,比如修改请求头、参数等
        // 如果不调用chain.doFilter,请求就会在这里被中断
        // 比如,一个简单的IP黑名单
        String clientIp = httpRequest.getRemoteAddr();
        if ("127.0.0.1".equals(clientIp)) { // 假设127.0.0.1是黑名单
            httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN); // 403 禁止
            httpResponse.getWriter().write("Access Forbidden for your IP!");
            return; // 阻止请求继续
        }

        chain.doFilter(request, response); // 将请求传递给下一个过滤器或目标资源

        // 请求处理完成后,可以在这里对响应进行后处理
        System.out.println("Filter 处理完成响应: " + httpRequest.getRequestURI());
        // 比如,添加一个自定义响应头
        httpResponse.setHeader("X-Processed-By", "MyBasicFilter");
    }

    @Override
    public void destroy() {
        System.out.println("MyBasicFilter 销毁...");
    }
}

Filter的优势在于其通用性,不依赖于任何框架,可以在任何Servlet容器中运行。但它的缺点也很明显,它对Spring等框架内部的组件(如Controller、Service)一无所知,无法直接操作Spring的上下文,也无法像HandlerInterceptor那样细粒度地控制到方法级别。

2. Aspect-Oriented Programming (AOP)

AOP是一种编程范式,它允许开发者定义“横切关注点”,并将其模块化。在Java中,Spring AOP和AspectJ是两种主要的AOP实现。虽然它们通常用于拦截方法调用,但也可以间接用于“拦截”请求。例如,你可以在一个Controller方法执行前后插入逻辑。

AOP的优点是它更关注于“在何时何地执行某个逻辑”,而不是“请求的生命周期”。它能够精确地在方法执行前、执行后、抛出异常后等时机插入代码,粒度更细。缺点是它通常作用于应用程序内部的方法调用,而不是直接作用于HTTP请求本身。

例如,一个简单的Spring AOP切面:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyControllerAspect {

    // 定义一个切入点,匹配所有在com.example.controller包下的方法
    @Pointcut("execution(* com.example.controller.*.*(..))")
    public void controllerMethods() {}

    @Around("controllerMethods()")
    public Object logAndMonitor(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        String methodName = joinPoint.getSignature().getName();
        System.out.println("AOP: 方法 " + methodName + " 开始执行...");

        Object result = null;
        try {
            result = joinPoint.proceed(); // 执行目标方法
            System.out.println("AOP: 方法 " + methodName + " 执行成功。");
        } catch (Throwable e) {
            System.err.println("AOP: 方法 " + methodName + " 执行异常: " + e.getMessage());
            throw e; // 重新抛出异常
        } finally {
            long endTime = System.currentTimeMillis();
            System.out.println("AOP: 方法 " + methodName + " 执行耗时: " + (endTime - startTime) + "ms");
        }
        return result;
    }
}

AOP和HandlerInterceptor在某些功能上有所重叠(比如日志和性能监控),但它们作用的层面不同。HandlerInterceptor作用于HTTP请求的生命周期,而AOP作用于方法调用的生命周期。在实际项目中,它们经常被结合使用,互为补充。

选择哪种拦截机制,很大程度上取决于你的项目架构、所使用的框架以及具体的需求。Spring项目通常首选HandlerInterceptor,而对于更底层或非Spring的Web应用,Servlet Filter则是不二之选。AOP则在需要对方法级别进行精细控制时显得尤为强大。

终于介绍完啦!小伙伴们,这篇关于《Java拦截网络请求,中间件实现全解析》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布文章相关知识,快来关注吧!

相关阅读
更多>
最新阅读
更多>
课程推荐
更多>