如何从application.properties读取值并设置为@RequestHeader默认值
解决方案:通过HttpServletRequestWrapper + Filter实现请求头默认值注入
要实现从application.properties读取配置作为请求头的默认值,核心思路是在请求到达Controller之前,通过Filter包装HttpServletRequest,注入默认的请求头值,具体步骤如下:
1. 创建可变请求头的HttpServletRequest包装类
继承HttpServletRequestWrapper,重写请求头相关方法,实现自定义的请求头存储逻辑:
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.util.*; public class MutableHttpServletRequest extends HttpServletRequestWrapper { private final Map<String, String> customHeaders; public MutableHttpServletRequest(HttpServletRequest request) { super(request); this.customHeaders = new HashMap<>(); } // 添加自定义请求头 public void putHeader(String name, String value) { this.customHeaders.put(name, value); } @Override public String getHeader(String name) { // 优先取自定义的请求头,没有的话再取原生请求头 String headerValue = customHeaders.get(name); if (headerValue != null) { return headerValue; } return ((HttpServletRequest) getRequest()).getHeader(name); } @Override public Enumeration<String> getHeaders(String name) { List<String> headers = new ArrayList<>(Collections.list(((HttpServletRequest) getRequest()).getHeaders(name))); String customHeader = customHeaders.get(name); if (customHeader != null) { headers.add(customHeader); } return Collections.enumeration(headers); } @Override public Enumeration<String> getHeaderNames() { Set<String> headerNames = new HashSet<>(Collections.list(((HttpServletRequest) getRequest()).getHeaderNames())); headerNames.addAll(customHeaders.keySet()); return Collections.enumeration(headerNames); } }
2. 创建Filter处理请求头注入
在Filter中读取配置文件的值,判断请求是否携带目标请求头,若没有则通过包装类注入默认值:
import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; @Component public class DefaultHeaderFilter implements Filter { @Value("${item.includePrice.value}") private String defaultIncludePrice; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(httpRequest); // 检查请求是否携带includePrice,没有则注入默认值 String includePrice = httpRequest.getHeader("includePrice"); if (includePrice == null || includePrice.isEmpty()) { mutableRequest.putHeader("includePrice", defaultIncludePrice); } // 传递包装后的请求到后续流程 chain.doFilter(mutableRequest, response); } // 初始化和销毁方法可留空 @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void destroy() {} }
3. 配置Filter拦截路径(可选,若需指定拦截范围)
如果需要只拦截特定路径的请求,可以通过FilterRegistrationBean注册Filter:
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<DefaultHeaderFilter> defaultHeaderFilterRegistration(DefaultHeaderFilter filter) { FilterRegistrationBean<DefaultHeaderFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(filter); // 指定拦截的API路径,比如只拦截/item开头的请求 registrationBean.addUrlPatterns("/item/*"); return registrationBean; } }
4. 修改Controller代码
此时请求中一定会包含includePrice请求头(要么是客户端传递的,要么是Filter注入的默认值),可以简化Controller的判断逻辑:
@PostMapping("/item") public String postBody(@RequestHeader String includePrice, @RequestBody SomeRequest someRequest) { // 无需再判断includePrice是否为null return "You searched for " + someRequest.getItemName(); }
为什么拦截器方案不可行?
原生的HttpServletRequest并没有提供修改请求头的方法,拦截器只能读取请求头,无法修改;而Filter可以在请求进入Servlet容器的早期阶段,通过包装HttpServletRequest替换成自定义的实现,从而实现请求头的修改和注入。
内容的提问来源于stack exchange,提问作者psprogrammer
相关产品推荐
相关产品推荐

