Spring Boot拦截器preHandle方法中添加自定义请求头的解决方案咨询
Alright, I’ve run into this exact issue before—trying to add a custom request header in a Spring HandlerInterceptor when the original request doesn’t have it, and you can’t modify the controller code that depends on it. Let’s break down how to fix this properly.
The core problem here is that the default HttpServletRequest implementation (like Tomcat’s Request class) doesn’t let you directly modify request headers—they’re treated as immutable once the request is received. To get around this, we need to wrap the original request in a custom HttpServletRequestWrapper that overrides header-related methods to include our custom value.
Step 1: Create a Custom Request Wrapper
First, we’ll build a wrapper class that lets us add custom headers while preserving all original request data:
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequestWrapper; import java.util.*; public class CustomHeaderRequestWrapper extends HttpServletRequestWrapper { private final Map<String, String> customHeaders; public CustomHeaderRequestWrapper(HttpServletRequest request) { super(request); this.customHeaders = new HashMap<>(); } // Method to add our custom header public void addHeader(String name, String value) { customHeaders.put(name, value); } @Override public String getHeader(String name) { // Check our custom headers first, fall back to original if not found String customValue = customHeaders.get(name); if (customValue != null) { return customValue; } return super.getHeader(name); } @Override public Enumeration<String> getHeaders(String name) { // Combine custom header with original headers List<String> headerValues = new ArrayList<>(); if (customHeaders.containsKey(name)) { headerValues.add(customHeaders.get(name)); } Enumeration<String> originalHeaders = super.getHeaders(name); while (originalHeaders.hasMoreElements()) { headerValues.add(originalHeaders.nextElement()); } return Collections.enumeration(headerValues); } @Override public Enumeration<String> getHeaderNames() { // Combine custom header names with original ones Set<String> allHeaderNames = new HashSet<>(customHeaders.keySet()); Enumeration<String> originalNames = super.getHeaderNames(); while (originalNames.hasMoreElements()) { allHeaderNames.add(originalNames.nextElement()); } return Collections.enumeration(allHeaderNames); } }
Step 2: Update Your HandlerInterceptor
Now, modify your KeyTaskInterceptor to wrap the request with our custom wrapper when your condition is met, and update the request context so downstream components (like your controller) use the wrapped version:
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.servlet.HandlerInterceptor; public class KeyTaskInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (/* Your custom condition here */) { // Wrap the original request and add the custom header CustomHeaderRequestWrapper wrappedRequest = new CustomHeaderRequestWrapper(request); wrappedRequest.addHeader("KeyCode", "Your-Custom-Value-Here"); // Update the request context to use our wrapped request ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attributes != null) { attributes.setRequest(wrappedRequest); } } return true; } }
Alternative: Use a Filter (More Reliable for Request Wrapping)
If you’re open to switching from an interceptor to a filter, this is often a more straightforward approach. Filters run earlier in the request lifecycle and are designed to modify request/response objects directly:
1. Create the Filter
import jakarta.servlet.*; import jakarta.servlet.http.HttpServletRequest; import java.io.IOException; public class KeyTaskFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; if (/* Your custom condition here */) { CustomHeaderRequestWrapper wrappedRequest = new CustomHeaderRequestWrapper(request); wrappedRequest.addHeader("KeyCode", "Your-Custom-Value-Here"); // Pass the wrapped request to the next filter/controller filterChain.doFilter(wrappedRequest, servletResponse); } else { // Use original request if condition isn't met filterChain.doFilter(request, servletResponse); } } // Optional: Implement init() and destroy() if needed }
2. Register the Filter (Spring Boot Example)
In Spring Boot, you can register the filter using a FilterRegistrationBean:
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FilterConfig { @Bean public FilterRegistrationBean<KeyTaskFilter> keyTaskFilter() { FilterRegistrationBean<KeyTaskFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new KeyTaskFilter()); // Specify URL patterns to apply this filter to registrationBean.addUrlPatterns("/*"); return registrationBean; } }
Why This Works
The custom wrapper overrides all the methods that controllers use to access request headers (getHeader, getHeaders, getHeaderNames). When your controller looks for the KeyCode header, it will first check our custom map and return the value we added, just like if it was sent by the frontend.
内容的提问来源于stack exchange,提问作者xarqt

