如何在 Ktor 内部重定向?

Posted

技术标签:

【中文标题】如何在 Ktor 内部重定向?【英文标题】:How to redirect internally in Ktor? 【发布时间】:2020-06-12 01:36:49 【问题描述】:

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

call.respondRedirect("relative/url")

根据 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 :(")

目标是客户端不应该发出 2 个请求,也不应该意识到重定向的发生。

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

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

【问题讨论】:

【参考方案1】:

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

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)

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

get("/foo") 
    call.redirectInternally("/bar")

【讨论】:

我喜欢!当我再次开始这个项目时,我会尝试一下。谢谢分享! 我已经尝试过解决类似问题的解决方案,但得到的答案是:500 Internal Server Error, "Request body has been used (received)."

以上是关于如何在 Ktor 内部重定向?的主要内容,如果未能解决你的问题,请参考以下文章

重定向到 Ktor 中的绝对 URL

如何在 Ktor 中调用内部端点?

Nuxt.js:如何重定向内部方法

如何在nginx创建临时重定向和永久重定向

如何在 nginx 服务器上做 301 重定向

如何做nginx的重定向