如何解决执行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请求和响应流程。
- 外部用户使用
GET /
在example.org端口80上向Host: example.org
发送HTTP请求。 - 负载均衡器获取请求,检查其规则并找到将请求定向到的内部服务器。
- 负载均衡器会创建新的HTTP请求,主要是复制传入的数据,但会更新
Host
标头并添加多个X-Forwarded-*
标头以保留有关代理请求的信息(有关特定信息,请参见here到GCP)。 - 该请求命中了您的服务器。此时,您可以分析
X-Forwarded-*
标头以查看您是否在反向代理后面,并获取由实际用户(例如原始主机)发送的实际查询所需的详细信息。 - 您可以设计HTTP响应,然后服务器将其发送回负载平衡器。
- 负载均衡器将此响应传递给外部用户。
请注意,尽管有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 举报,一经查实,本站将立刻删除。