其实这是一个很简单的问题,答案当然是可以的。
有时候,我们在查看页面的response headers
的时候,会发现相同域名下,不同的域名有时候返回的server
是不同的,也就是他们其实是被部署在不同类型的服务器上。
实现的原理其实也很简单,不同类型的服务器都会提供反向代理功能。将满足一定条件的请求转发到另一台服务器上即可。
最近工作的内容也涉及到类似的功能,前提是这样的:我们的产品是一个简单的 CMS 产品,也就是每一个客户会拥有自己的独立域名,使用我们的网站产品,但是代码是同一套部署。
比如客户主站的域名是:www.ag.com
。我们所有的产品可以部署到用户提供的一个子域名上: jobs.ag.com
。这样用户只需要简单的将jobs.ag.com
放到他们的网站入口上就可以了。
直到产品上线前一两个月,得到的需求是,客户不希望有子域名的存在,希望域名能够统一。也就是说,用户会在他们服务器上加设一层代理,所有的www.ag.com/jobs
请求都会转发到jobs.ag.com
上。
其实表面上看起来比较简单,只是一层简单的反向代理。但是细想,其实有很多问题。因为所有跟绝对路径相关的都会出问题。
举个例子:当用户访问:www.as.com/jobs/login
点击登录以后,我们会跳转到/profile
页面。一旦加了这一层反向代理以后,实际上的跳转页面也会变成:www.as.com/profile
。然后代码就会走到客户的服务器上导致 404 出现。
因为我们实际上需要保证跳转的页面是:jobs.as.com/profile
或者www.as.com/jobs/profile
. 这样才能保证,请求会到达 CMS 系统的服务器。
另外一个现实是,我们的CMS系统最开始就没有考虑过根路径会有变化这个可能性。也就是说在系统里的跳转都是相当随意的。而且系统也比较老旧,前端同时存在jQuery和angularJS 的处理。
所以要解决这个问题就得包含以下几个方面:
- 假设这个CMS站的
prefix
是jobs
。(其实需要让不同的客户可以配置) - 确保所有的请求都支持prefix,也就是说:
jobs.as.com/jobs/
和jobs.as.com
能够同时处理。(这是为了方便处理绝对路径跳转和充分支持客户的反向代理) - 确保服务器端的页面能够正确跳转。
- 确保 HTML/CSS 中的资源请求标签(如:
a
,<script>
,img
)标签能够正确处理。 - 确保 angularJS 中的页面跳转能够正确处理。(
ng-href
) - 确保 JS 中的跳转能够正确处理。(
window.location
)
下面再来一个个解释如何处理这些问题的
-
确保所有的请求都支持
prefix
这个其实很简单,不同的web
框架有不同的处理方案。简单的说,就是服务器接收到request
的时候判断一下是否包含你定义的prefix
(这里是:jobs
), 有的话去掉。这样就能保证所有
jobs.ag.com/jobs/*
的请求都会和jobs.ag.com/*
相同。不同的框架也有不同的方案,比如修改routes
层。只需要确保所有的页面都能支持这个prefix
, 甚至需要包含静态文件(js, css, images)。 -
确保服务器端的页面能够正确跳转。
所有服务器端的内容其实都相对比较简单。首先我们可能需要直到服务器端跳转的原理。
当我们请求A页面
,A页面
又跳转到B页面
。实际上发生的事情是:- 请求
A页面
的时候,A页面
会在Response headers
里添加一个字段叫做location
。 - 浏览器如果接收到
Response Headers
里的location
字段,会重新发送一个GET
请求到这个URL
。
而且大多数
web 框架
其实都会封装一个方法叫做doRedirection()
,而你所有做的其实也就是在 doRedirection() 这里加上一层添加prefix
在跟路径的逻辑。 - 请求
-
确保 HTML/CSS 中的资源请求标签。
这也是相对比较简单的,体力活。
在服务器端 response 之前截取到生成的 HTML,CSS 文件。穷举出所有肯能包含web 请求
的标签,a
,image
等等,然后判断是否为绝对路径,是的话,加上prefix
. -
确保 JS 中的跳转能够正确处理。(window.location)
-
确保 angularJS 中的页面跳转能够正确处理。(ng-href)