HttpServletRequestWrapper详解

HttpServletRequestWrapper 是 Java Servlet 规范中的一个类,它实现了 HttpServletRequest 接口,并包装了原始的 HttpServletRequest 对象 。它的主要作用是作为装饰器模式(Decorator Pattern) 的实现,允许开发者在不修改原始请求对象的前提下,对请求的行为进行增强或修改。


1. 核心作用

1.1 装饰器模式

  • HttpServletRequestWrapper 本身不直接实现所有功能,而是将大部分方法调用委托给原始请求对象
  • 开发者可以继承这个类,并重写特定方法来修改请求的某些行为。

1.2 保护原始请求对象

  • 通过包装器,原始请求对象不会被直接修改,避免对应用的其他部分产生副作用。

2. 实际应用场景

2.1 修改请求参数(Parameter Overriding)

问题场景

需要动态修改请求参数(例如:过滤敏感词汇、统一参数格式等)。

解决方案

继承 HttpServletRequestWrapper,重写 getParameter()getParameterValues() 等方法。

java 复制代码
public class CustomRequestWrapper extends HttpServletRequestWrapper {
    private Map<String, String[]> modifiedParams;

    public CustomRequestWrapper(HttpServletRequest request) {
        super(request);
        modifiedParams = new HashMap<>(request.getParameterMap());
    }

    // 重写参数获取方法
    @Override
    public String getParameter(String name) {
        String[] values = modifiedParams.get(name);
        return values != null ? values[0] : null;
    }

    @Override
    public String[] getParameterValues(String name) {
        return modifiedParams.get(name);
    }

    // 添加修改参数的方法
    public void setParameter(String name, String value) {
        modifiedParams.put(name, new String[]{value});
    }
}

2.2 多次读取请求体(Body Caching)

问题场景
HttpServletRequest 的输入流(getInputStream())只能读取一次,但在过滤器中可能需要多次读取(例如:日志记录、签名验证等)。

解决方案

通过包装器缓存请求体内容,后续读取时直接返回缓存数据。

java 复制代码
public class CachedBodyRequestWrapper extends HttpServletRequestWrapper {
    private byte[] cachedBody;

    public CachedBodyRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        // 将请求体内容读取到缓存
        InputStream inputStream = request.getInputStream();
        this.cachedBody = IOUtils.toByteArray(inputStream);
    }

    @Override
    public ServletInputStream getInputStream() {
        final ByteArrayInputStream inputStream = new ByteArrayInputStream(body);
        // 返回 ServletInputStream
        return new ServletInputStream() {

            @Override
            public int read() {
                return inputStream.read();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {}

            @Override
            public int available() {
                return body.length;
            }

        };
    }

    @Override
    public BufferedReader getReader() {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.cachedBody);
        return new BufferedReader(new InputStreamReader(byteArrayInputStream));
    }
}

2.3 请求信息增强

问题场景

需要为请求添加额外信息(例如:用户身份信息、请求ID等),但不想修改原始参数。

解决方案

通过包装器添加自定义方法或属性。

java 复制代码
public class EnhancedRequestWrapper extends HttpServletRequestWrapper {
    private String userId;

    public EnhancedRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getUserId() {
        return userId;
    }
}

2.4 安全过滤(XSS防护)

问题场景

需要对请求参数进行转义,防止XSS攻击。

解决方案

重写参数获取方法,对返回值进行转义。

java 复制代码
public class XSSSafeRequestWrapper extends HttpServletRequestWrapper {
    public XSSSafeRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        return escapeXSS(value);
    }

    private String escapeXSS(String value) {
        // 实现XSS转义逻辑
        return value.replace("<", "&lt;").replace(">", "&gt;");
    }
}

3. 使用流程

  1. 创建自定义包装器 :继承 HttpServletRequestWrapper,重写需要修改的方法。

  2. 在过滤器或拦截器中包装原始请求

    java 复制代码
    public class MyFilter implements Filter {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
            HttpServletRequest wrappedRequest = new CustomRequestWrapper((HttpServletRequest) request);
            chain.doFilter(wrappedRequest, response);
        }
    }
  3. 在后续处理中使用包装后的请求:Servlet 或 Controller 将使用修改后的请求对象。


4. 注意事项

  • 不要破坏原始请求:包装器应确保未修改的方法正常委托给原始请求。
  • 性能考虑:缓存请求体或大量参数可能增加内存消耗,需权衡使用。
  • 谨慎修改关键信息:如修改 URL 或方法类型可能影响容器行为。

5. 总结

HttpServletRequestWrapper 是 Servlet 开发中一个强大的工具,主要用于:

  • 修改请求参数
  • 缓存请求体
  • 增强请求信息
  • 实现安全过滤

通过包装器模式,它提供了一种非侵入式的请求处理方式,是过滤器(Filter)和拦截器(Interceptor)中的常见技术。

相关推荐
莫得感情 o12 小时前
并发 14 · 收官:虚拟线程与结构化并发
java·并发
聚美智数13 小时前
图片水印-图片剪裁-图片缩放API接口介绍
java·服务器·数据库
xierui12312313 小时前
AI Agent 隐私架构:本地化重点为什么是登录态与执行权限
java·人工智能·网络安全·架构
cfm_291413 小时前
Spring AI Tool 调用架构全解
java·人工智能·spring
sun༒14 小时前
Spring @Scheduled 定时任务详解:Cron表达式、执行顺序、优先级与并行调度
java·后端·spring
一次旅行14 小时前
DeepSeek‑V4‑Flash‑Vision‑Exp 小白入门实战|3种传图方式、完整可跑代码、避坑排障
java·前端·人工智能
野生技术架构师14 小时前
Spring Boot 实现数据脱敏:自定义注解 + Jackson 序列化器
java·spring boot·后端
AI人工智能+电脑小能手14 小时前
大白话说Java设计模式-28-模板方法模式(业务实战篇)
java·设计模式·模板方法模式·spring源码·订单系统·代码复用
奥莱维14 小时前
KNX酒店方案_KNX专用线与高端酒店技术逻辑
java·服务器·前端·数据库
工业一体机老司机14 小时前
Linux工业一体机自启动服务配置:systemd服务单元编写与开机优化实战
java·linux·服务器