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("<", "<").replace(">", ">");
}
}
3. 使用流程
-
创建自定义包装器 :继承
HttpServletRequestWrapper
,重写需要修改的方法。 -
在过滤器或拦截器中包装原始请求 :
javapublic class MyFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { HttpServletRequest wrappedRequest = new CustomRequestWrapper((HttpServletRequest) request); chain.doFilter(wrappedRequest, response); } }
-
在后续处理中使用包装后的请求:Servlet 或 Controller 将使用修改后的请求对象。
4. 注意事项
- 不要破坏原始请求:包装器应确保未修改的方法正常委托给原始请求。
- 性能考虑:缓存请求体或大量参数可能增加内存消耗,需权衡使用。
- 谨慎修改关键信息:如修改 URL 或方法类型可能影响容器行为。
5. 总结
HttpServletRequestWrapper
是 Servlet 开发中一个强大的工具,主要用于:
- 修改请求参数
- 缓存请求体
- 增强请求信息
- 实现安全过滤
通过包装器模式,它提供了一种非侵入式的请求处理方式,是过滤器(Filter)和拦截器(Interceptor)中的常见技术。