1. 概述
在使用Servlet API开发Java Web应用时,HttpServletRequest对象是处理HTTP请求的核心组件。它提供了访问请求参数、请求头和属性的能力。
请求参数通常由HTTP客户端提供,但某些场景下我们需要在请求被处理前以编程方式修改或添加参数。⚠️ 注意:HttpServletRequest本身没有提供直接修改参数的方法。本文将介绍如何通过扩展其功能来实现参数设置。
2. Maven依赖
除了标准的Java Servlet API:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
我们还会在参数清理场景中使用commons-text库:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.10.0</version>
</dependency>
3. 核心Servlet组件
3.1. HttpServletRequest
封装HTTP请求的核心类,提供对请求参数、头信息等的访问。
3.2. HttpServletRequestWrapper
HttpServletRequest的装饰器实现,允许我们动态扩展原始请求对象的功能。
3.3. Filter
请求处理链中的拦截器,能在请求到达Servlet前修改请求和响应对象。
4. 参数清理:防止XSS攻击
通过编程方式设置参数的典型场景是清理用户输入,防止XSS攻击。核心思路是转义HTML特殊字符,确保恶意脚本无法执行。
4.1. 实现步骤
4.1.1. 创建过滤器
@WebFilter(urlPatterns = {"/sanitize/with-sanitize.jsp"})
public class SanitizeParametersFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpReq = (HttpServletRequest) request;
chain.doFilter(new SanitizeParametersRequestWrapper(httpReq), response);
}
}
4.1.2. 实现请求包装器
public class SanitizeParametersRequestWrapper extends HttpServletRequestWrapper {
private final Map<String, String[]> sanitizedMap;
public SanitizeParametersRequestWrapper(HttpServletRequest request) {
super(request);
sanitizedMap = Collections.unmodifiableMap(
request.getParameterMap().entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> Arrays.stream(entry.getValue())
.map(StringEscapeUtils::escapeHtml4)
.toArray(String[]::new)
)));
}
@Override
public Map<String, String[]> getParameterMap() {
return sanitizedMap;
}
@Override
public String[] getParameterValues(String name) {
return Optional.ofNullable(getParameterMap().get(name))
.map(values -> Arrays.copyOf(values, values.length))
.orElse(null);
}
@Override
public String getParameter(String name) {
return Optional.ofNullable(getParameterValues(name))
.map(values -> values[0])
.orElse(null);
}
}
关键点:
- ✅ 使用
StringEscapeUtils.escapeHtml4
转义HTML实体 - ✅ 重写所有参数访问方法确保一致性
- ✅ 返回不可修改的Map(符合Servlet规范)
4.1.3. 测试JSP
The text below comes from request parameter "input":<br/>
<%=request.getParameter("input")%>
4.2. 效果对比
未启用过滤器
访问URL:
http://localhost:8080/sanitize/without-sanitize.jsp?input=<script>alert('Hello');</script>
结果:弹出JavaScript警告框
启用过滤器
访问URL:
http://localhost:8080/sanitize/with-sanitize.jsp?input=<script>alert('Hello');</script>
结果:HTML实体被转义并安全显示
The text below comes from request parameter "input":
<script>alert('Hello');</script>
5. 第三方模块参数注入
当需要与无法修改源码的第三方模块交互时,可通过编程方式注入所需参数。
5.1. 实现方案
5.1.1. 第三方模块示例
<%
String localeStr = request.getParameter("locale");
Locale currentLocale = (localeStr != null ? new Locale(localeStr) : null);
%>
The language you have selected: <%=currentLocale != null ? currentLocale.getDisplayLanguage(currentLocale) : " None"%>
5.1.2. 参数注入Servlet
@WebServlet(name = "LanguageServlet", urlPatterns = "/setparam/lang")
public class LanguageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
SetParameterRequestWrapper requestWrapper = new SetParameterRequestWrapper(request);
requestWrapper.setParameter("locale", Locale.getDefault().getLanguage());
request.getRequestDispatcher("/setparam/3rd_party_module.jsp")
.forward(requestWrapper, response);
}
}
5.1.3. 参数设置包装器
public class SetParameterRequestWrapper extends HttpServletRequestWrapper {
private final Map<String, String[]> paramMap;
public SetParameterRequestWrapper(HttpServletRequest request) {
super(request);
paramMap = new HashMap<>(request.getParameterMap());
}
@Override
public Map<String, String[]> getParameterMap() {
return Collections.unmodifiableMap(paramMap);
}
public void setParameter(String name, String value) {
paramMap.put(name, new String[] {value});
}
// getParameter()和getParameterValues()实现同前例
}
5.2. 执行结果
访问/setparam/lang
时,系统自动注入默认语言参数:
The language you have selected: English
6. 总结
通过本文我们掌握了:
- ✅ 使用HttpServletRequestWrapper扩展请求功能
- ✅ 通过Filter拦截并修改请求
- ✅ 两种典型应用场景:
- 参数清理(安全增强)
- 第三方模块参数注入
这些技术为处理特殊业务需求提供了灵活的解决方案。完整代码示例可在GitHub获取。