编写ServletFilter单元测试无法获取Servlet响应内容问题排查
问题背景
我负责一组SpringBoot服务的开发工作,项目中实现了一个基于ESAPI对请求做HTML编码的ServletFilter,用于防范跨站脚本攻击。近期我调整了该过滤器的数据编码逻辑,自认为修改正确,但在编写单元测试验证修改效果时遇到问题,不确定预期逻辑是否合理。
我使用Spring提供的MockHttpServletRequest、MockHttpServletResponse类编写了简易测试用例,核心验证目标是确认Servlet响应的内容与预期值一致,测试方法代码如下:
@Test public void protectAgainstDoubleEncoding() throws Exception { String input = "{\"foo\": \"bar AT&T foo\"}"; MockHttpServletRequest servletRequest = new MockHttpServletRequest(); servletRequest.setContentType(MediaType.APPLICATION_JSON); servletRequest.setCharacterEncoding("UTF-8"); servletRequest.setContent(input.getBytes()); MockHttpServletResponse servletResponse = new MockHttpServletResponse(); servletResponse.setCharacterEncoding("UTF-8"); servletResponse.setContentType(MediaType.APPLICATION_JSON); MockFilterConfig config = new MockFilterConfig(); MockFilterChain filterChain = new MockFilterChain(); xssFilter.init(config); xssFilter.doFilter(servletRequest, servletResponse, filterChain); assertThat(servletResponse.getContentAsString()).isEqualTo(input); }
问题现象
当前暂不展示xssFilter的具体实现代码。实际运行测试时发现,调用servletResponse.getContentAsString()方法返回值为空字符串,无法完成响应内容的断言校验。
问题根因
- 无参构造的
MockFilterChain实例没有绑定任何目标Servlet,执行完配置的XSSFilter后,不会执行任何写入响应的逻辑。按照Servlet规范,Filter本身只是请求/响应的加工层,不会主动生成响应内容,正常流程中Filter执行完毕后会将请求交给后续链路的Servlet处理,由Servlet负责将业务返回内容写入Response,当前测试链路缺失了这个核心环节,自然响应内容为空。 - 额外排查点:如果补全了写入响应的逻辑后依然拿不到内容,需要检查XSSFilter的响应包装逻辑是否正确——如果Filter通过自定义ResponseWrapper缓存了下游写入的内容做编码处理,必须在
doFilter方法返回前、过滤器逻辑收尾阶段,将Wrapper中缓存的处理后内容写回原始Response对象,否则外层无法拿到处理后的响应内容。
调整方案
构造MockFilterChain时传入一个简单的Servlet实现,模拟下游业务组件写入响应的动作,即可正常校验过滤器的处理逻辑,调整后的核心代码如下:
// 替换原有空参构造的MockFilterChain,传入模拟业务Servlet MockFilterChain filterChain = new MockFilterChain((request, response) -> { // 模拟下游Controller/Servlet将目标内容写入响应的动作 response.getWriter().write(input); });
替换后重新执行测试,即可正常从servletResponse.getContentAsString()拿到经过过滤器处理后的响应内容,完成断言校验。
内容的提问来源于stack exchange,提问作者David M. Karr
相关产品推荐
相关产品推荐

