在 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
我希望在控制器中执行端点方法之前使用 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