首先,最好您的代理或负载均衡器可以为您执行此检查和重定向,因为它了解公共 URL,并且在第一次与用户联系时是一个更简单的过程。但是,您也可以在服务器端执行此操作,但稍微复杂一些。
您正在检查的标志,context.request().isSSL
仅对 Vertx-web 的传入连接有效,不考虑最终用户与代理或负载均衡器的连接。您需要使用X-Forwarded-Proto
标题(有时X-Forwarded-Scheme
)并检查用户的实际协议。并且只有当该标头不存在时您才可以使用context.request().isSSL
您还需要外部化您自己的 URL,以便能够在服务器端重定向到浏览器可以用来找到您的公共 URL。
首先,这个 Stack Overflow 答案中有一个 Kotlin 函数RoutingContext.externalizeUrl()
,您将在这里需要它:
我有一个 Vertx 请求,我需要计算一个外部可见(公共)URL https://stackoverflow.com/questions/39564199/i-have-a-vertx-request-and-i-need-to-calculate-an-externally-visible-public-ur/39564200#39564200
然后知道您的公共 URL,您可以使用以下处理程序,该处理程序具有预期公共 HTTPS 端口的默认值(默认 443 将从 URL 中消失),哪种形式的重定向(i.e. 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()
}
}
}