需求:
需求是这样的:有一个 xxx-yyy-zzz-publish.test-d.com.cn/view/scene?… 页面需要用iframe嵌入到 业务系统 ayewu.test.com.cn(192.168.1.8) 里。
分析:
分析了一下:xxx-yyy-zzz-publish.test-d.com.cn 也就是 xxx-yyy-zzz.test-d.com.cn 系统嘛,这个系统摸索过一段时间,很熟悉啊(没想到在这挖了个坑)。业务系统是https协议,而嵌入页面只支持http,嵌入大概率Mixed Content被浏览器拦截。于是考虑使用nginx反向代理,将http代理为https,并挂在 9112 接口上。配置如下相当简单:
location / {
proxy_pass http://xxx-yyy-zzz.test-d.com.cn;
proxy_cookie_domain ~.* $host; -- 登录后,服务器返回的cookie domian不对,修改一下
}
登录 ayewu.test.com.cn:9112 测试了一下,没什么问题,系统登录一切正常。
代理配置好后,来了一个优先级更高的任务,于是这个需求暂时被搁置了。一段时间后,继续开始处理。
掉坑里 - 奇怪的301问题:
在 业务系统 ayewu.test.com.cn 上,加上iframe,配置上地址 ayewu.test.com.cn:9112/view/scene?… ,一片空白。F12打开调试器,返回了301错误。
HTTP/1.1 301 Moved Permanently
Location: http://zzz-publish?id=123456&publish=1
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
于是根据 301返回的Location字段 将地址改为 ayewu.test.com.cn:9112/zzz-publish… ,仍然是301。
为什么 ayewu.test.com.cn:9112 能打开,而单独的页面却不行,难道是页面单独做了限制。回想过去配置反向代理,有时会配置Host,怀疑是没有设置Host,一顿尝试,竟然走通了。
location / {
proxy_pass http://xxx-yyy-zzz.test-d.com.cn;
proxy_cookie_domain ~.* $host; -- 登录后,服务器返回的cookie domian不对,修改一下
proxy_set_header Host xxx-yyy-zzz-publish.test-d.com.cn;
}
但是 ayewu.test.com.cn:9112 却打不开了.
思考
为什么加了Host可以了,现象也很奇怪,不太理解,于是测试如下场景:
- 不使用代理,直接访问 xxx-yyy-zzz-publish.test-d.com.cn/view/scene?… ,去掉Host就有问题,否则正常
GET /view/scene?id=275817090068500008&publish=1 HTTP/1.1
Host: xxx-yyy-zzz-publish.test-d.com.cn
- 修改配置,将请求代理到测试环境 192.168.1.3,在测试环境监听接收到的内容
location / {
proxy_pass http://192.168.1.3:10022;
proxy_cookie_domain ~.* $host; -- 登录后,服务器返回的cookie domian不对,修改一下
proxy_set_header Host xxx; -- 改变此处,测试区别
}
2.1. 不带 proxy_set_header Host 时,测试环境接收到的请求:
GET /view/scene?id=123456&publish=1 HTTP/1.0
Host: 192.168.1.3:10022
也就是说不带参数时,Host实际是proxy_pass地址,即xxx-yyy-zzz-publish.test-d.com.cn
2.2. 配置 proxy_set_header Host $proxy_host 时,测试环境接收到的请求:
GET /view/scene?id=123456&publish=1 HTTP/1.0
Host: 192.168.1.3:10022
配置 $proxy_host时,Host实际是proxy_pass地址
2.3. 配置 proxy_set_header Host $host 时,测试环境接收到的请求:
GET /view/scene?id=123456&publish=1 HTTP/1.0
Host: 192.168.1.8
配置 $host时,Host实际是nginx的ip (直接访问了 ayewu.test.com.cn 系统的 ip地址 192.168.1.8,使用域名结果可能不同)
2.4. 配置 proxy_set_header Host $http_host 时,测试环境接收到的请求:
GET /view/scene?id=123456&publish=1 HTTP/1.0
Host: 192.168.1.8:9112
配置 $http_host,Host实际是nginx的ip + 端口
- 按照测试结果,2.1 与 1 的效果是一样的。所以,即使不配置Host也应该能走通啊,百思不得其解。
问题的根源
暂时不管,过了一段时间,再次回顾配置。发现 xxx-yyy-zzz-publish.test-d.com.cn, xxx-yyy-zzz.test-d.com.cn 并不是同一个(这是两个不同的服务。test-d.com.cn单独弄了一个publish服务,来对外发布页面)。
为什么修改Host访问就正常了呢?
测试ip地址:
C:\>ping xxx-yyy-zzz-publish.test-d.com.cn
正在 Ping xxx-yyy-zzz-publish.test-d.com.cn [192.168.2.7] 具有 32 字节的数据:
来自 192.168.2.7 的回复: 字节=32 时间=28ms TTL=62
C:\>ping xxx-yyy-zzz.test-d.com.cn
正在 Ping xxx-yyy-zzz.test-d.com.cn [192.168.2.7] 具有 32 字节的数据:
来自 192.168.2.7 的回复: 字节=32 时间=2ms TTL=62
很明显,两个地址的ip其实是相同的,服务端 通过Host来转发给不同的内部服务。
未配置proxy_set_header Host时,proxy_pass起决定作用。publish服务的地址当然也就访问不了。
配置proxy_set_header Host后,proxy_pass虽然是域名,但只起到了提供ip地址的作用,proxy_set_header Host将Host覆盖了,成为真正起决定作用的配置。这也是为什么配置Host后,代理的test-d.com.cn首页就打不开了,此时反向代理实际指向的是publish服务。