微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

执行https重定向时ktor重定向到0.0.0.0

如何解决执行https重定向时ktor重定向到0.0.0.0

我已将http重定向添加到我的Ktor应用程序中,并将其重定向https://0.0.0.0而不是实际域的https

@ExperimentalTime
fun Application.module() {

    if (ENV.env != LOCAL) {
        install(ForwardedHeaderSupport)
        install(XForwardedHeaderSupport)
        install(HttpsRedirect)
    }

拦截路由并打印出主机

    routing {

            intercept(ApplicationCallPipeline.Features) {
            val host = this.context.request.host()

我似乎为主机获得了0:0:0:0:0:0:0:0

我是否需要向Google Cloud的负载均衡器添加任何特殊标头才能使此https重定向正常工作?似乎没有选择正确的主机

解决方法

由于您的Ktor服务器隐藏在反向代理的后面,因此它不与站点的“外部”主机绑定。 Ktor具有特定的feature to handle working behind reverse proxy,因此在配置和引用install(XForwardedHeaderSupport)以获得实际主机的过程中,它应该与request.origin.remoteHost一样简单。

让我们尝试看看发生了什么。

您在http://example.org下创建服务。在example.org主机的端口80上,有一个负载平衡器。它处理所有传入的流量,并将其路由到自身后面的服务器。 您的实际应用程序正在另一台虚拟机上运行。它有自己的IP地址,位于您的云内部,并且可由负载均衡器访问。

让我们看看此系统的HTTP请求和响应流程。

  1. 外部用户使用GET /在example.org端口80上向Host: example.org发送HTTP请求。
  2. 负载均衡器获取请求,检查其规则并找到将请求定向到的内部服务器。
  3. 负载均衡器会创建新的HTTP请求,主要是复制传入的数据,但会更新Host标头并添加多个X-Forwarded-*标头以保留有关代理请求的信息(有关特定信息,请参见here到GCP)。
  4. 该请求命中了您的服务器。此时,您可以分析X-Forwarded-*标头以查看您是否在反向代理后面,并获取由实际用户(例如原始主机)发送的实际查询所需的详细信息。
  5. 您可以设计HTTP响应,然后服务器将其发送回负载平衡器。
  6. 负载均衡器将此响应传递给外部用户。

请注意,尽管有RFC 7239用于指定有关请求转发的信息,但GCP负载均衡器似乎使用了事实上的标准X-Forwarded-*标头,因此您需要XForwardedHeaderSupport而不是{{1 }}(请注意其他X)。

,

因此,似乎Google Cloud Load Balancer发送了错误的标头或Ktor读取了错误的标头,或两者都有。

我尝试过

    install(ForwardedHeaderSupport)
    install(XForwardedHeaderSupport)
    install(HttpsRedirect)

    //install(ForwardedHeaderSupport)
    install(XForwardedHeaderSupport)
    install(HttpsRedirect)

    install(ForwardedHeaderSupport)
    //install(XForwardedHeaderSupport)
    install(HttpsRedirect)

    //install(ForwardedHeaderSupport)
    //install(XForwardedHeaderSupport)
    install(HttpsRedirect)

所有这些组合都在另一个项目上运行,但是该项目使用的是Ktor的较旧版本(这是1.4 rc发行的版本),并且该项目还使用了较旧的Google Cloud负载均衡器设置。

所以我决定自己动手。 此行将记录您的请求中附带的所有标头,

                log.info(context.request.headers.toMap().toString())

然后选择相关内容并建立一个https重定向:

routing {

    intercept(ApplicationCallPipeline.Features) {
        if (ENV.env != LOCAL) {

            log.info(context.request.headers.toMap().toString())

            // workaround for call.request.host that contains the wrong host
            // and not redirecting properly to the correct https url
            val proto = call.request.header("X-Forwarded-Proto")
            val host = call.request.header("Host")
            val path = call.request.path()

            if (host == null || proto == null) {
                log.error("Unknown host / port")
            } else if (proto == "http") {
                val newUrl = "https://$host$path"
                log.info("https redirecting to $newUrl")

                // redirect browser
                this.context.respondRedirect(url = newUrl,permanent = true)
                this.finish()
            }
        }
    }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。