如何在Micronaut过滤器中为传入请求添加自定义请求头
问题解答
一、decoration(装饰)和modification(修改)的区别
- modification(修改):指直接修改原有请求/响应对象的内部属性。Micronaut 设计上默认 HttpRequest 为不可变对象,直接修改原对象会触发
UnsupportedOperationException,也就是你遇到的报错。 - decoration(装饰):指不改动原有请求/响应对象本身,通过装饰器模式生成一个新的包装对象,在包装对象中扩展你需要的属性(比如新增请求头),再将包装对象传递给过滤器链后续节点,原请求对象全程保持不变,符合框架的不可变设计规范。
二、实现JWT校验并新增请求头的方案
你之前遇到mutate()方法抛异常,是因为你主动把原请求包装成了HttpRequestWrapper,这个类没有重写mutate()默认实现,才触发了报错。直接使用原生请求的mutate()方法即可,Micronaut 内置的请求实现已经重写了该方法,会返回一个新的可变请求实例,符合装饰的要求。
完整实现代码如下:
1. 过滤器实现
@Filter(Filter.MATCH_ALL_PATTERN) public class SecurityFilter implements HttpServerFilter { private static final Logger LOG = LoggerFactory.getLogger(SecurityFilter.class); // 注入你自己实现的JWT校验工具类 private final JwtValidator jwtValidator; public SecurityFilter(JwtValidator jwtValidator) { this.jwtValidator = jwtValidator; } @Override public Publisher<MutableHttpResponse<?>> doFilter(final HttpRequest<?> request, final ServerFilterChain chain) { // 从请求头提取Bearer Token Optional<String> tokenOpt = request.getHeaders().getAuthorization() .filter(authStr -> authStr.startsWith("Bearer ")) .map(authStr -> authStr.substring(7)); // 无有效token直接返回401 if (tokenOpt.isEmpty()) { return Publishers.just(HttpResponse.status(HttpStatus.UNAUTHORIZED)); } try { // 校验JWT合法性,提取租户ID字段,这里逻辑你可以根据自己的JWT结构调整 String tenantId = jwtValidator.validateAndGetTenantId(tokenOpt.get()); // 装饰原请求,新增X-Tenant-Id头,不会改动原请求对象 HttpRequest<?> decoratedRequest = request.mutate() .header("X-Tenant-Id", tenantId); // 将装饰后的请求传入过滤器链 return chain.proceed(decoratedRequest); } catch (Exception e) { // JWT校验失败返回401 LOG.warn("JWT 校验不通过", e); return Publishers.just(HttpResponse.status(HttpStatus.UNAUTHORIZED)); } } @Override public int getOrder() { return ServerFilterPhase.SECURITY.order(); } }
2. 控制器取值
你原有控制器的代码不需要做任何改动,@Header("X-Tenant-Id") 可以直接读取到过滤器中新增的请求头:
@Get(uri = "/{id}", produces = MediaType.APPLICATION_JSON) public Optional<Item> findById(@PathVariable("id") final String id, @Header("X-Tenant-Id") final String tenantId) { return service.findById(id, tenantId); }
内容的提问来源于stack exchange,提问作者jokarl
相关产品推荐
相关产品推荐

