如何在router.route("/api/*").handler中使用协程? [英] How to use coroutine inside the router.route("/api/*").handler?

查看:506
本文介绍了如何在router.route("/api/*").handler中使用协程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在路由处理程序lambda中使用协程,如下所示:

I am trying to use coroutine inside the route handler lambda as follows:

  private suspend fun createRoutes(router: Router, auth: OAuth2Auth): Unit {


    val oauth2 = OAuth2AuthHandler.create(vertx, auth)
    val authz = KeycloakAuthorization.create()


    router.route().handler(LoggerHandler.create())

    router.route("/api/*").handler(oauth2)

     router.route("/api/greet").handler {

      println(RoleBasedAuthorization.create("ad-admins").match(it.user()))

      authz.getAuthorizations(it.user()).await()
    }

  }

编译器在authz.getAuthorizations(it.user()).await()上抱怨Suspension functions can be called only within coroutine body. 我在做什么错了?

The compiler complains on authz.getAuthorizations(it.user()).await() about Suspension functions can be called only within coroutine body. What am I doing wrong?

整个代码:

class MainVerticle : CoroutineVerticle() {

  private suspend fun initConfig(): JsonObject {
    val yamlConfigOpts = ConfigStoreOptions()
      .setFormat("yaml")
      .setType("file")
      .setConfig(JsonObject().put("path", "config.yaml"))

    val configRetrieverOpts = ConfigRetrieverOptions()
      .addStore(yamlConfigOpts)

    val configRetriever = ConfigRetriever.create(vertx, configRetrieverOpts)

    return configRetriever.config.await()
  }


  private suspend fun createJwtAuth(): OAuth2Auth =

    KeycloakAuth.discover(
      vertx,
      OAuth2Options()
        .setFlow(OAuth2FlowType.AUTH_CODE)
        .setClientID("svc")
        .setClientSecret("9d782e45-67e7-44b1-9b74-864f45f9a18f")
        .setSite("https://oic.dev.databaker.io/auth/realms/databaker")
    ).await()


  private suspend fun createRoutes(router: Router, auth: OAuth2Auth): Unit {


    val oauth2 = OAuth2AuthHandler.create(vertx, auth)
    val authz = KeycloakAuthorization.create()


    router.route().handler(LoggerHandler.create())

    router.route("/api/*").handler(oauth2)

    router.route("/api/greet").handler {

      println(RoleBasedAuthorization.create("ad-admins").match(it.user()))

      authz.getAuthorizations(it.user()).await()
    }

  }


  private suspend fun server(router: Router): HttpServer {
    val server = vertx.createHttpServer()

    return server.requestHandler(router)
      .listen(8080)
      .onSuccess {
        println("HTTP server started on port ${it.actualPort()}")
      }
      .onFailure {
        println("Failed to start the server. Reason ${it.message}")
      }
      .await()
  }


  override suspend fun start() {

    val router = Router.router(vertx)


    createRoutes(router, createJwtAuth())
    server(router)

  }

}

提示:我正在使用 Vertx 4.0.0 RC1

推荐答案

由于未在挂起函数中调用authz.getAuthorizations(it.user()).await(),因此编译器:从Vert.x Web路由处理程序中调用.

The compiler because authz.getAuthorizations(it.user()).await() is not invoked in a suspended function: it is invoked from the Vert.x Web route handler.

您必须使用launch包装您的调用:

You must wrap your invocation with launch:

router.route("/api/greet").handler {
  println(RoleBasedAuthorization.create("ad-admins").match(it.user()))
  launch {
    authz.getAuthorizations(it.user()).await()
  }
}

鉴于此代码是在CoroutineVerticle中定义的,协程将绑定到verticle上下文(以及在verticle的事件循环中调用的代码).

Given this code is defined in a CoroutineVerticle, the coroutine will be bound to the verticle context (and the code invoked on the verticle's event loop).

这篇关于如何在router.route("/api/*").handler中使用协程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆