如何在 Ktor 中进行内部重定向?

TWi*_*Rob 5 redirect response.redirect ktor

我想知道是否有办法在 Ktor 内部进行内部重定向、重新路由或响应转发。

call.respondRedirect("relative/url")
Run Code Online (Sandbox Code Playgroud)

根据permantent: Boolean标志发送 HTTP 302 或 301。我正在寻找无需使用 HTTP 即可完成相同操作的东西,只需在 Ktor 内部即可。这是我想要实现的一些伪路由:

get("/foo") {
    if (call.parameters["something"] != null) {
        call.respondText("Yay, something!")
    } else {
        call.respondRedirect("/bar") // except without relying on client to handle HTTP redirects.
    }
}
get("/bar") {
    call.respondText("No thing :(")
}
Run Code Online (Sandbox Code Playgroud)

目标是客户端不应该发出 2 个请求,并且不应该知道重定向的发生。

注意:我知道我可以为/bar的主体提取一个函数并调用它,而不是responsdRedirect. 但是,我想让 Ktor 处理它,以便它与所有拦截器一起经历所有必要的生命周期和管道。这是为了确保将其视为外部请求(网络往返除外)。

我正在寻找类似 Express.js 的东西req.app.handle(req, res),如本答案的前半部分所示: https: //stackoverflow.com/a/48790319/253468。我还无法理解的一个潜在解决方案是TestApplicationEngine.handleRequest(in io.ktor:ktor-server-test-host) 正在做 with pipeline.execute。我想我可以调用call.application.execute(),问题是如何构造该ApplicationCall对象。请注意,这是用于生产用途的,所以没有TestApplicationCall

Ale*_*man 2

您可以通过使用call.application.execute带有克隆call对象的函数在 Ktor 中执行类似的操作。为了方便起见,我们定义扩展函数来进行内部重定向:

suspend fun ApplicationCall.redirectInternally(path: String) {
    val cp = object: RequestConnectionPoint by this.request.local {
        override val uri: String = path
    }
    val req = object: ApplicationRequest by this.request {
        override val local: RequestConnectionPoint = cp
    }
    val call = object: ApplicationCall by this {
        override val request: ApplicationRequest = req
    }

    this.application.execute(call)
}
Run Code Online (Sandbox Code Playgroud)

在这里,它创建一个对象的副本ApplicationCall,其中包含请求的替换路径。我使用委托来避免样板代码。您可以使用redirectInternally这样的函数:

get("/foo") {
    call.redirectInternally("/bar")
}
Run Code Online (Sandbox Code Playgroud)