[英]Using reactive @ServerRequestFilter with RestClient in Quarkus
当dev-mode
被激活时,我想在我的请求中添加一些自定义身份验证标头。 这应该使我的开发更容易,因为我不必手动将它们添加到自己身上。
我发现的是方法注释ServerRequestFilter ,它在达到 controller 级别之前拦截正在进行的请求。 带注释的 function 提供了ContainerRequestContext
参数,我可以在其中轻松添加我的标题。
现在的问题:要知道自定义标头值,我必须对 API 进行外部 rest 调用(我为此使用了RestClient )。 由于我使用的是响应式库,因此我得到了异常org.jboss.resteasy.reactive.common.core.BlockingNotAllowedException
因为这个调用。
由于我使用的是 Kotlin,因此我试图将我的方法标记为可暂停。 But this lead to a build error Method 'preCall$suspendImpl of class 'com.kaz.request.service.RequestInterceptor' cannot be static as it is annotated with '@org.jboss.resteasy.reactive.server.ServerRequestFilter'
这是我的代码:
@ApplicationScoped
class RequestInterceptor @Inject constructor(val authService: AuthService) {
@ServerRequestFilter
suspend fun preCall(requestContext: ContainerRequestContext) {
validateIdTokenHeader(requestContext)
}
private suspend fun validateIdTokenHeader(requestContext: ContainerRequestContext) {
val isTokenHeaderAbsent = requestContext.getHeaderString(Headers.X_ID_TOKEN) == null
val isDevModeEnabled = LaunchMode.current() == LaunchMode.DEVELOPMENT
if (isTokenHeaderAbsent && !isDevModeEnabled) {
throw AuthExceptions.ID_TOKEN_IS_ABSENT
} else {
injectDevUserIdToken(requestContext)
}
}
private suspend fun injectDevUserIdToken(requestContext: ContainerRequestContext) {
// This call is making the request and block
val idToken = authService.getIdToken("someHash")
requestContext.headers.putSingle(Headers.X_ID_TOKEN, idToken)
}
}
我还尝试在我的 RestClient 中使用Mutiny
。 我订阅了 Uni 并在结果可用时添加了 header。 但后来我遇到了问题,在 header 可以添加到请求之前,我的控制器/端点已经被调用。
端点可能如下所示:
@Path("hello/{id}")
@GET
suspend fun get(
//This header is what I want to add automatically, when dev mode is active.
@RestHeader(Headers.X_ID_TOKEN) idToken: UserIdToken,
@RestPath id: UUID,
@Context httpRequest: HttpServerRequest
): Response {
val request = RequestDTO(id, excludeFields, idToken.userId)
val envelope = service.findById(request)
return ResponseBuilder.build(httpRequest, envelope)
}
您的实现中的某些东西阻止了 IO 。 所以你可以尝试找到它并用Uni包装它,或者你可以用@Blocking注解标记方法,然后过滤器将在工作线程上运行。
如何创建一个延迟 Uni 并将其发送到工作池?
val idToken = Uni.createFrom().item { authService.getIdToken("someHash") }
.runSubscriptionOn(Infrastructure.getDefaultWorkerPool())
或使用默认的 io 协程调度程序调用阻塞代码
withContext(Dispatchers.IO){
authService.getIdToken("someHash")
}
最后,也许使用 Vertx.executeBlocking 将是最简单的方法
vertx.executeBlocking(Uni.createFrom().item {
authService.getIdToken("someHash")
})
有时不仅要阅读在线文档页面,还要阅读相应 class 的内联注释。
ServerRequestFilter.java
说:
The return type of the method must be either be of type void, Response, RestResponse, Optional<Response>, Optional<RestResponse>, Uni<Void>, Uni<Response> or Uni<RestResponse>.
...
Uni<Void> should be used when filtering needs to perform a
non-blocking operation but the filter cannot abort processing. Note
that Uni<Void> can easily be produced using: Uni.createFrom().nullItem()
所以入口点 function 也必须返回一个 Uni,而不仅仅是 RestClient。 像下面这样改变它就足够了
@ServerRequestFilter
fun preCall(requestContext: ContainerRequestContext) : Uni<Void> {
//Here I return a Uni<Void> back using Uni.createFrom().nullItem()
return validateIdTokenHeader(requestContext)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.