发布于 

当Kong遇上redirect 302重定向

在线上环境中,常常因为网络限制等,通过nginx做反向代理,将不同的服务通过同一个入口提供给请求方…

事情呢是这样的

为了方便配置和使用更丰富的功能,我们在测试环境使用了kong来做反向代理网关。使用浏览器访问http://ip_a:port_a/app,使用konga页面配置将请求转发到http://ip_b:port_b/app

在大多数场景下,工作良好。今天在配置新的应用时突然发生问题,现象如下:

  1. 浏览器访问http://ip_a:port_a/app
  2. 浏览器地址栏跳转到http://ip_b:port_b/app/...
  3. 由于本地与ip_b的网络不通,因此很显然请求失败了

观察network信息,可以发现,这是因为在请求ip_a:port_a时,后台返回了一个302重定向请求,因此浏览器按照返回的Location地址发起新的请求。那么解决这个问题的关键在于让重定向的地址依然是ip_a:port_a,通过有网络权限的kong所在的服务器来转发请求报文。

Nginx的解决办法

假如我们使用的是nginx,那么可以使用关键字proxy_redirect来将302重定向请求的Location地址修改为我们想要的代理地址,关键配置如下

1
2
3
4
5
6
7
server {
listen port_a;
location /app {
proxy_pass http://ip_b:port_b/app;
proxy_redirect http://ip_b:port_b/app/ http://ip_a:port_a/app/;
}
}

如上配置,proxy_redirect会将302返回报文中的Location http://ip_b:port_ b/app/...修改为http://ip_a:port_a/app/...再返回给请求端。

Kong下的解决办法

Kong其实就是加强版的nginx嘛,既然nginx可以配置,那Kong肯定也行。

然而,搜索了一下,发现Kong的设计者这么回复:

Kong的设计理念对UI和重定向并不友好,实际上,他并不建议使用kong来作为网站的反向代理吧啦吧啦…

总之,它更适合于作为后台接口间的报文转发网关。所以,你想直接使用konga等页面配置来实现proxy_redirect的功能,那是不行滴。

再谷歌一下,发现其实很多人都遇到同样的问题,有同样的需求。主要参考了这个Issue找到的解决方案:https://github.com/Kong/kong/issues/3503

kong确实是个加强版的nginx,我们在Kong服务器上去找,其实是能找到nginx.conf这个配置文件的(还有nginx-kong.conf),但是与我们熟悉的配置不同,这里的nginx.conf并不是直接配置就可以用上了,因为它实际上是由nginx.lua(nginx_kong.lua)脚本生成出来的。即使你修改了配置文件中的内容,重启kong的时候,又会重新生成nginx的配置文件,将你的配置覆盖。

因此,我们去观察nginx.lua以及nginx_kong.lua脚本文件,在它写配置的模板的合适的地方,加上我们的proxy_redirect配置即可。添加保存后,重启kong,再去看新生成的nginx配置文件,就可以发现已经修改了,再去请求http://ip_a:port_a就不会被重定向到ip_b:port_b去了。

你当然可以直接写死如

1
proxy_redirect http://ip_b:port_b/app/ http://ip_a:port_a/app/;

但这样也可能觉得太死板,以后增加个ip_a转到ip_c的,又要增加个配置。因此,可以考虑将路径中的host参数化,充分利用nginx的路径规则匹配能力,比如

1
proxy_redirect ~^(http://[^:]+):\d+(/.+)$ $2;