【问题标题】:In Vertx I need to redirect all HTTP requests to the same URL but for HTTPS在 Vertx 中,我需要将所有 HTTP 请求重定向到相同的 URL,但对于 HTTPS
【发布时间】:2017-01-26 15:15:15
【问题描述】:

我在 Koltin 中编写了一个 Vertx-web 处理程序,它将我收到的任何 HTTP 请求重定向到 HTTPS,并且我使用 context.request().isSSL 来确定该请求是否不是 SSL,并且在我把我的负载均衡器后面的代码。如果负载均衡器通过 HTTPS 与我的 Vertx-web 服务器通信,那么它认为所有用户请求都是 HTTPS,即使它们不是。如果我将负载均衡器更改为通过 HTTP 与 Vertx-web 通信,那么即使用户已经在使用 HTTPS,每个请求都会被无休止地重定向。

然后我还看到另一个问题,即使用 context.request().absoluteURI() 的重定向转到了私有地址,而不是用户实际与之交谈的公开地址。

Vertx-web 中是否有一个我缺少的处理程序可以做到这一点,或者一些惯用的方法来解决这个问题?我应该只从 JavaScript 执行此操作,因为它会看到真实的用户地址而不是尝试服务器端重定向吗?

我正在使用 Kotlin 进行编码,因此该语言的任何示例都很棒!

注意: 这个问题是作者(Self-Answered Questions)有意编写和回答的,以便在SO中分享有趣问题的解决方案。

【问题讨论】:

    标签: kotlin vert.x


    【解决方案1】:

    首先,最好您的代理或负载均衡器可以为您执行此检查和重定向,因为它知道公共 URL,并且在与用户第一次联系时是一个更简单的过程。但是,您也可以在服务器端进行,但要稍微复杂一些。

    您正在检查的标志 context.request().isSSL 仅对到 Vertx-web 的传入连接有效,并且不考虑最终用户与您的代理或负载平衡器的连接。您需要使用X-Forwarded-Proto 标头(有时是X-Forwarded-Scheme)并检查用户的实际协议。只有当该标题不存在时,您才能使用context.request().isSSL

    您还需要外部化您自己的 URL,以便能够在服务器端重定向到浏览器可以用来找到您的公共 URL。

    首先,RoutingContext.externalizeUrl() 的 Stack Overflow 答案中有一个 Kotlin 函数,您将在这里需要它:
    I have a Vertx request and I need to calculate an externally visible (public) URL

    然后知道您的公共 URL,您可以使用以下处理程序,该处理程序具有预期公共 HTTPS 端口的默认值(默认 443 将从 URL 中消失),重定向的形式(即 302 ),以及如果路由应该失败或继续的任何例外情况:

    fun Route.redirectToHttpsHandler(publicHttpsPort: Int = 443, redirectCode: Int = 302, failOnUrlBuilding: Boolean = true) {
        handler { context ->
            val proto = context.request().getHeader("X-Forwarded-Proto")
                    ?: context.request().getHeader("X-Forwarded-Scheme")
            if (proto == "https") {
                context.next()
            } else if (proto.isNullOrBlank() && context.request().isSSL) {
                context.next()
            } else {
                try {
                    val myPublicUri = URI(context.externalizeUrl())
                    val myHttpsPublicUri = URI("https", 
                            myPublicUri.userInfo, 
                            myPublicUri.host, 
                            publicHttpsPort,
                            myPublicUri.rawPath, 
                            myPublicUri.rawQuery, 
                            myPublicUri.rawFragment)
                    context.response().putHeader("location", myHttpsPublicUri.toString()).setStatusCode(redirectCode).end()
                } catch (ex: Throwable) {
                    if (failOnUrlBuilding) context.fail(ex)
                    else context.next()
                }
            }
        }
    }
    

    一个更简单的版本可能是只信任context.externalizeUrl 类,看看它是否有正确的协议和端口,如果没有则重定向:

    fun Route.simplifiedRedirectToHttpsHandler(publicHttpsPort: Int = 443, redirectCode: Int = 302, failOnUrlBuilding: Boolean = true) {
        handler { context ->
            try {
                val myPublicUri = URI(context.externalizeUrl())
                if (myPublicUri.scheme == "http") {
                    val myHttpsPublicUri = URI("https",
                            myPublicUri.userInfo,
                            myPublicUri.host,
                            publicHttpsPort,
                            myPublicUri.rawPath,
                            myPublicUri.rawQuery,
                            myPublicUri.rawFragment)
                    context.response().putHeader("location", myHttpsPublicUri.toString()).setStatusCode(redirectCode).end()
                }
                else {
                    context.next()
                }
            } catch (ex: Throwable) {
                if (failOnUrlBuilding) context.fail(ex)
                else context.next()
            }
        }
    }
    

    【讨论】:

    • 新手问题在这里,我将如何注册(或使用)simplifiedRedirectorToHttpsHandler?例如,我的典型设置是:private fun createRouter() = Router.router(vertx).apply { route().handler(BodyHandler.create()) ... 更新:没关系,我明白了 :) Router.router(vertx).apply { route().redirectToHttpsHandler() route().handler(BodyHandler.create())
    猜你喜欢
    • 2018-05-05
    • 2014-06-30
    • 1970-01-01
    • 1970-01-01
    • 2017-04-30
    • 2016-04-08
    • 2011-05-04
    • 2016-11-17
    相关资源
    最近更新 更多