You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

  1. 未区分请求路径,所有请求都添加固定的USER值,不符合需求;
  2. @Order(Ordered.LOWEST_PRECEDENCE)设置了最低优先级,可能被其他Filter覆盖;
  3. 仅重写了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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 22:09:59