使用ContainerRequestContext添加请求头后HttpServletRequest获取为null问题咨询
问题解答
为什么HttpServletRequest拿不到你添加的请求头?
你的理解确实存在偏差,核心原因是JAX-RS框架和Servlet容器的请求处理是分层的:
ContainerRequestContext是JAX-RS框架内部的请求上下文,你在这里添加的头信息只存在于JAX-RS的处理链中,@HeaderParam、@Context HttpHeaders这类JAX-RS原生API都是直接从这个上下文读取数据,所以能拿到值。HttpServletRequest是Servlet容器层的原生请求对象,JAX-RS默认不会把自身上下文的修改同步到这个对象里。两者相当于同一个请求的不同视图,JAX-RS在Servlet之上做了封装,独立维护自己的请求状态。
解决方案与最佳实践
1. 优先用JAX-RS原生API获取头信息
既然@HeaderParam("header_name")和@Context HttpHeaders能正常拿到值,这就是JAX-RS推荐的最佳实践,完全符合框架的设计逻辑,没必要强行用HttpServletRequest。
2. 非要用HttpServletRequest?手动同步
如果业务场景必须从HttpServletRequest读取,你得自己把JAX-RS里加的头同步过去。注意HttpServletRequest本身的头是不可直接修改的,得用包装类:
public class CustomRequestWrapper extends HttpServletRequestWrapper { private final Map<String, String> customHeaders; public CustomRequestWrapper(HttpServletRequest request, Map<String, String> customHeaders) { super(request); this.customHeaders = customHeaders; } @Override public String getHeader(String name) { String customVal = customHeaders.get(name); return customVal != null ? customVal : super.getHeader(name); } @Override public Enumeration<String> getHeaders(String name) { List<String> headers = new ArrayList<>(); String customVal = customHeaders.get(name); if (customVal != null) { headers.add(customVal); } Enumeration<String> originalHeaders = super.getHeaders(name); while (originalHeaders.hasMoreElements()) { headers.add(originalHeaders.nextElement()); } return Collections.enumeration(headers); } @Override public Enumeration<String> getHeaderNames() { Set<String> names = new HashSet<>(customHeaders.keySet()); Enumeration<String> originalNames = super.getHeaderNames(); while (originalNames.hasMoreElements()) { names.add(originalNames.nextElement()); } return Collections.enumeration(names); } }
然后在JAX-RS过滤器里,获取原生HttpServletRequest并包装替换:
@Provider public class CustomRequestFilter implements ContainerRequestFilter { @Context private HttpServletRequest servletRequest; @Override public void filter(ContainerRequestContext requestContext) throws IOException { // 先给JAX-RS上下文加头 String headerName = "header_name"; String headerValue = "header_value"; requestContext.getHeaders().add(headerName, headerValue); // 包装Servlet请求,同步头信息 Map<String, String> customHeaders = new HashMap<>(); customHeaders.put(headerName, headerValue); HttpServletRequest wrappedRequest = new CustomRequestWrapper(servletRequest, customHeaders); // 替换上下文里的请求对象(不同JAX-RS实现方式有差异,比如Jersey可以用RequestContextHolder,或者提前在Servlet过滤器里做包装) } }
这种方式比较麻烦,不同JAX-RS实现(比如Jersey、RESTEasy)的处理细节不一样,非必要别用。
3. 换用Servlet过滤器(如果场景允许)
如果你的需求就是要修改Servlet层的请求头,直接写Servlet过滤器就行,不用JAX-RS过滤器。这样修改的头会直接存在HttpServletRequest里,JAX-RS的API也能正常读取。
内容的提问来源于stack exchange,提问作者Aditya Jain
相关产品推荐
相关产品推荐

