Spring Boot按路径添加请求头至控制器前的问题求助
Spring Boot 根据请求路径添加请求头的解决方案
问题说明
需要在Spring Boot中实现:当请求路径为/v1/users/**时,自动添加请求头x-operation:USER;当路径为/v1/pet/**时,添加请求头x-operation:PET,且必须在请求到达控制器前完成。此前尝试的Filter、HandlerInterceptor、WebMvcConfigurer三种方式均未生效。
原有方法失效原因分析
方法1:WebMvcConfigurer + HandlerInterceptor
代码中使用request.setAttribute("x-operation", "USER")设置的是请求属性,而非请求头。控制器中通过@RequestHeader获取的是HTTP请求头,自然无法拿到属性值。
方法2:Filter + HttpServletRequestWrapper
- 未区分请求路径,所有请求都添加固定的
USER值,不符合需求; @Order(Ordered.LOWEST_PRECEDENCE)设置了最低优先级,可能被其他Filter覆盖;- 仅重写了
getHeader()方法,未覆盖getHeaders()和getHeaderNames(),部分场景下控制器会调用这些方法导致无法获取自定义头。
方法3:SecurityConfig + StaticHeadersWriter
StaticHeadersWriter的作用是给响应添加头,而非修改请求头,方向完全错误;且配置的路径/v1/user/**与需求的/v1/users/**不符。
正确解决方案:Filter + 完善的HttpServletRequestWrapper
Filter是请求链路中最早的处理环节,能确保在控制器前完成请求头修改,同时需要完整实现HttpServletRequestWrapper的相关方法。
1. 自定义HttpServletRequestWrapper
public class CustomHeaderRequestWrapper extends HttpServletRequestWrapper { private final Map<String, String> customHeaders; public CustomHeaderRequestWrapper(HttpServletRequest request, Map<String, String> customHeaders) { super(request); this.customHeaders = customHeaders; } @Override public String getHeader(String name) { // 先查自定义头,没有再查原请求头 String customHeader = customHeaders.get(name.toLowerCase()); if (customHeader != null) { return customHeader; } return super.getHeader(name); } @Override public Enumeration<String> getHeaders(String name) { List<String> headers = new ArrayList<>(); String customHeader = customHeaders.get(name.toLowerCase()); if (customHeader != null) { headers.add(customHeader); } Enumeration<String> originalHeaders = super.getHeaders(name); while (originalHeaders.hasMoreElements()) { headers.add(originalHeaders.nextElement()); } return Collections.enumeration(headers); } @Override public Enumeration<String> getHeaderNames() { Set<String> headerNames = new HashSet<>(); headerNames.addAll(customHeaders.keySet()); Enumeration<String> originalHeaderNames = super.getHeaderNames(); while (originalHeaderNames.hasMoreElements()) { headerNames.add(originalHeaderNames.nextElement()); } return Collections.enumeration(headerNames); } }
2. 自定义Filter并配置优先级
@Component @Order(Ordered.HIGHEST_PRECEDENCE) // 设置最高优先级,确保最先执行 public class CustomHeaderFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; String requestURI = httpRequest.getRequestURI(); Map<String, String> customHeaders = new HashMap<>(); // 根据路径判断添加对应的请求头 if (requestURI.startsWith("/v1/users/")) { customHeaders.put("x-operation", "USER"); } else if (requestURI.startsWith("/v1/pet/")) { customHeaders.put("x-operation", "PET"); } // 包装请求 HttpServletRequestWrapper requestWrapper = new CustomHeaderRequestWrapper(httpRequest, customHeaders); chain.doFilter(requestWrapper, response); } @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void destroy() {} }
3. 控制器测试
在控制器中可以通过@RequestHeader获取自定义添加的请求头:
@RestController @RequestMapping("/v1/users") public class UserController { @GetMapping("/info") public String getUserInfo(@RequestHeader("x-operation") String operation) { return "Operation: " + operation; // 应该返回 "Operation: USER" } } @RestController @RequestMapping("/v1/pet") public class PetController { @GetMapping("/info") public String getPetInfo(@RequestHeader("x-operation") String operation) { return "Operation: " + operation; // 应该返回 "Operation: PET" } }
注意事项
- 路径判断使用
startsWith而非精确匹配,确保覆盖所有子路径; - Filter优先级设置为
Ordered.HIGHEST_PRECEDENCE,避免被其他Filter修改请求; - 必须完整重写
getHeader()、getHeaders()、getHeaderNames()三个方法,覆盖所有获取请求头的场景。
内容的提问来源于stack exchange,提问作者Divakar V
相关产品推荐
相关产品推荐

