背景
业务接入https,后端服务需要需要客户端的请求schma是老版本http,还是新版的https请求。这里通常采用的方案是通过X-Forwarded-Proto头来识别:
X-Forwarded-Proto (XFP) 是一个事实上的标准首部,用来确定客户端与代理服务器或者负载均衡服务器之间的连接所采用的传输协议(HTTP 或 HTTPS)。在服务器的访问日志中记录的是负载均衡服务器与服务器之间的连接所使用的传输协议,而非客户端与负载均衡服务器之间所使用的协议。为了确定客户端与负载均衡服务器之间所使用的协议, X-Forwarded-Proto 就派上了用场。
通常在ng中通过设置XFP来指定URI的scheme信息,如:
proxy_set_header X-Forwarded-Proto $scheme;
然后后端可以通过读取header X-Forwarded-Proto来获得对应的scheme。
但是现网的接入环境会比较复杂,通常存在多层反向代理的情况,这种简单粗暴的方式就不灵验了。
一个比较常见的https请求路径如下:
User-Agent —[https]—> haproxy(公司级接入) —[http]—> nginx(业务级接入) —[http]—> apache/php(后端服务接入)
最外层的接入收到User-Agent的https请求,但在内部和nginx的交互协议为http,所以nginx取到的scheme值就是http了,而非原始的https。 php(后端)也就无法知道真实的schema了。
解决方案
修改配置如下:
map $http_x_forwarded_proto $thescheme {
default $scheme;
https https;
}
proxy_set_header X-Forwarded-Proto $thescheme;
与之前的解决方案不同,不是将XFP设置为固定的scheme值,而是通过计算得出scheme。
map配置的意思是先判断是否已经存在XFP的header信息,如果是https则透传,否则使用连接的scheme。在最外层的反向代理中,没有XFP的header信息,所以会写入request,后续的接入层会逐步透传,一直到后端服务。