同一个域名,能访问不同服务器上的资源吗?

2,461 阅读4分钟

其实这是一个很简单的问题,答案当然是可以的。
有时候,我们在查看页面的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站的prefixjobs。(其实需要让不同的客户可以配置)
  • 确保所有的请求都支持prefix,也就是说:jobs.as.com/jobs/jobs.as.com能够同时处理。(这是为了方便处理绝对路径跳转和充分支持客户的反向代理)
  • 确保服务器端的页面能够正确跳转。
  • 确保 HTML/CSS 中的资源请求标签(如:a, <script>, img)标签能够正确处理。
  • 确保 angularJS 中的页面跳转能够正确处理。(ng-href
  • 确保 JS 中的跳转能够正确处理。(window.location)

下面再来一个个解释如何处理这些问题的

  1. 确保所有的请求都支持prefix
    这个其实很简单,不同的web框架有不同的处理方案。简单的说,就是服务器接收到request的时候判断一下是否包含你定义的prefix(这里是:jobs), 有的话去掉。

    这样就能保证所有jobs.ag.com/jobs/*的请求都会和jobs.ag.com/*相同。不同的框架也有不同的方案,比如修改routes层。只需要确保所有的页面都能支持这个 prefix, 甚至需要包含静态文件(js, css, images)。

  2. 确保服务器端的页面能够正确跳转。
    所有服务器端的内容其实都相对比较简单。首先我们可能需要直到服务器端跳转的原理。
    当我们请求 A页面A页面又跳转到 B页面。实际上发生的事情是:

    • 请求 A页面的时候,A页面会在 Response headers 里添加一个字段叫做 location
    • 浏览器如果接收到 Response Headers里的 location 字段,会重新发送一个 GET 请求到这个 URL

    而且大多数 web 框架其实都会封装一个方法叫做 doRedirection(),而你所有做的其实也就是在 doRedirection() 这里加上一层添加 prefix 在跟路径的逻辑。

  3. 确保 HTML/CSS 中的资源请求标签。
    这也是相对比较简单的,体力活。
    在服务器端 response 之前截取到生成的 HTML,CSS 文件。穷举出所有肯能包含web 请求的标签,a,image 等等,然后判断是否为绝对路径,是的话,加上 prefix.

  4. 确保 JS 中的跳转能够正确处理。(window.location)

  5. 确保 angularJS 中的页面跳转能够正确处理。(ng-href)