今天是 1024 程序猿的节日,今天不加班,回家加俩菜。
问题
昨天同事报出一个问题,给某家客户部署测试环境时遇到一个问题,他们访问该测试环境时完全正常,但是客户却不能访问。这是为什么呢?
原来是这样的,测试环境部署在阿里云上,包括两个系统,称他们分别是系统 A 和系统 B 吧。系统 A 通过https://customer.exmaple.com
访问,系统 B 作为系统 A 的子系统以iframe
方式嵌入到系统 A,并且通过https://customer.exmaple.com:8010
访问。部署完成之后我们同事正常访问,但是客户能访问系统 A,但是不能访问被iframe
嵌入系统 B。通过浏览器控制台可以看到报错.
Failed to load resource: net::ERR_TUNNEL_CONNECTION_FAILED.
解决
从报错的信息上看,隧道连接失败,隧道还不通,也就是请求就没有发送到服务器端去。我很快注意到系统 B 使用https
协议和 8010 端口,并猜想会不会https
协议必须使用 443 端口。我部署https
系统较少,没有看到或留意非 443 端口的https
应用。但是这个猜测很快被同事证明是错误的,因为我们的另外一个客户也是这样部署的,但是能够正常访问,突然感觉自己的网络方面的知识还是很欠缺的,其实这个也是很容易推断出来的,因为https
协议就是在 http 协议的基础上加了 SSL。http 协议支持的端口https
也应该支持。
请求根本就没有发送到服务器端去,不可能是服务器端的问题,这也被另一个现象佐证:我们同事可以正常访问。可以确定是客户网络问题,考虑到 8010 端口的https
实在少见,猜测是客户网络设置中禁止了非 443 端口的https
协议,那么怎么解决这个问题呢?让用户调整网络设置当然是最简单的,但是客户公司是整个集团统一设置的网络安全策略,想修改一定要有足够理由才行,在这之前还是想想有没有其他方案吧。
如果系统 A 和系统 B 使用相同的https
协议,相同的 443 端口,但是不同的域名呢?很快就找到 CTO 申请了一个customer-s.example.com
,部署之后发现上面的错误没有了,系统 B 的页面可以访问了,但是页面还是出不来,系统 B 的请求大多报错了。
Uncaught Type Error: Cannot read property ‘job’ of undefined
从浏览器端的错误信息可以看出该页面没有给出合适的初始化数据。经过后端同事诊断之后发现是系统 A 的Cookie
没有带过去,所以请求出现错误。啊?这是什么道理?访问系统 B 为什么要让浏览器自动带上系统 A 设置的Cookie
?
原来系统 A 和系统 B 并没有实现单点登录,而是系统 A 在即将打开系统 B 的iframe
时,首先调用系统 B 的登录接口换取登录URL
和token
,并在iframe
中打开系统 B,系统 B 的后端没有完备的数据给客户端使用,还会通过http
请求从系统 A 中获取数据,而系统 A 不知道系统 B 的服务器端程序要获取哪个用户的数据,怎么办呢?
猜测故事是这样的,开发阶段两个系统使用相同的 localhost 域名使用不同的端口,同时部署在本地,调试系统 B 的服务器端代码时发现原来可以获得系统 A 设置的Cookie
,那我把系统 A 的Cookie
带上去访问系统 A 的接口,模拟了一个浏览器请求,不就可以系统 A 获取当前用户的数据了吗?这样也就不需要系统 A 单独为系统 B 开发接口了,就这么办了。这里不去评价糟糕的设计,乱七八糟的设计最终也算是跑通了。
终于说到了这篇文章的主题了,Cookie
的作用域是整个域名,跨协议(HTTP
或HTTPS
,可以指定Cookie
仅适用于HTTPS
),跨端口共享。了解更详细内容请参考RFC6265。这是我以前没有注意到的,又长知识了。
由于解耦两个系统的工作量较大,目前还是采取跟客户沟通,对HTTPS
协议开放某个非 433 的端口。
总结
- 在解决问题过程中暴露了我两个知识点上的欠缺。
HTTPS
协议和HTTP
协议一样,可以绑定在不同的端口上。Cookie
的作用域是整个域名,跨协议跨端口共享。- 在遇到复杂系统通信时,需要做一些架构评审,防止出现上面提到的很不专业的处理方法。