在 Micronaut 中的 QueryValue 绑定之前拦截

Intercept prior to QueryValue binding in Micronaut

我希望在控制器中执行端点方法之前使用 HttpServerFilter 修改传入请求。在我的请求中,我有 @QueryValue 绑定。看起来这些绑定的执行发生在 HttpServerFilter 之前,所以如果我想修改查询参数,我将无法这样做。

@QueryValue 绑定之前,有什么地方可以拦截和修改请求吗?

可以通过HttpServerFilter解决,但是你应该在匹配的路由中更新参数值,而不是在请求中。这是因为 RoutingInBoundHandler 首先尝试满足路由的参数要求,然后执行过滤器链。请参阅下面的示例如何执行此操作:

调用修改服务的过滤器:

@Filter("/hello/**")
public class ModifyRequestFilter implements HttpServerFilter {
    private final ModifyRequestService service;

    public ModifyRequestFilter(ModifyRequestService service) {
        this.service = service;
    }

    @Override
    public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
        return service.modify(request)
                .switchMap(aBoolean -> chain.proceed(request));
    }
}

修改关键代码的服务:((NettyHttpRequest<?>) request).getMatchedRoute().getVariableValues().put("value", "modified in filter");:

@Singleton
public class ModifyRequestService {
    Flowable<Boolean> modify(HttpRequest<?> request) {
        return Flowable.fromCallable(() -> {
            ((NettyHttpRequest<?>) request).getMatchedRoute().getVariableValues().put("value", "modified in filter");
            return true;
        }).subscribeOn(Schedulers.io());
    }
}

和控制器:

@Controller("/hello")
public class HelloController {
    @Get("/")
    public String index(@QueryValue String value) {
        return "Hello " + value;
    }
}

另一种选择是使用自己的容器 class 来存储要使用自己的类型转换器修改的值。

例如CustomValue class作为值容器:

public class CustomValue {
    private String value;

    public CustomValue(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

这是将 CharSequence 转换为 CustomValue 实例的自定义值转换器的注册器:

@Singleton
@BootstrapContextCompatible
public class CustomConverterRegistrar implements TypeConverterRegistrar {
    @Override
    public void register(ConversionService<?> conversionService) {
        conversionService.addConverter(CharSequence.class, CustomValue.class, 
            s -> new CustomValue(s + "-updated"));
    }
}

这里是控制器的例子:

@Controller("/hello")
public class HelloController {
    @Get("/in-query")
    public String inQuery(@QueryValue CustomValue value) {
        return "Hello " + value.getValue();
    }

    @Get("/in-path/{value}")
    public String inPath(CustomValue value) {
        return "Hello " + value.getValue();
    }
}

卷曲测试结果:

$ curl http://localhost:8080/hello/in-query/?value=test
Hello test-updated
$ curl http://localhost:8080/hello/in-path/testFromPath
Hello testFromPath-updated