比方说,你有一个在设计方面很出色的平台上建立的网站,它可以在example.com 。但这个平台在博客方面有缺陷。所以你想,"如果我可以使用一个不同的博客平台,并把它放在example.com/blog ?"
大多数人会告诉你,这有悖于DNS和网站的工作原理,而应该使用子域。但是,将你的内容保留在根域名上有一些好处,而这些好处是我们在子域名上得不到的。
有一种方法可以在同一个URL上提供两个不同的平台。我将向你展示秘诀,这样,在本文结束时,我们将使blog.example.com 作为example.com/blog 。
为什么你要这样做
因为你在这里,你可能已经知道为什么这是一条值得追求的道路。但是,我想确保你在这里是为了做这件事的主要原因。搜索引擎优化。看看这14个案例研究,当人们将他们的子域转移到子目录时,显示了积极的结果。你希望你的博客和你的域名能够共享SEO价值。把它放在一个子域上会在某种程度上切断两者的联系。
这是我的理由,结果是合并了两个平台,主域在WordPress上,子域在Drupal上。但这个教程是不分平台的--它几乎适用于任何平台。
也就是说,我们在本教程中涉及的Cloudflare方法与Shopify不兼容,除非你为Cloudflare的企业计划付费。这是因为Shopify也使用Cloudflare,不允许我们在其免费定价层上代理流量。
第0步(预览)
在我开始之前,我想先解释一下将要发生的事情的高层次。简而言之,我们将有两个网站:我们的主网站(example.com )和子域(blog.example.com )。我以 "博客 "为例,但在我的案例中,我需要在Drupal中投放不同类型的内容。但博客是典型的使用案例。
这种方法依赖于使用Cloudflare的DNS和一个额外的小东西,它将提供神奇的效果。我们要告诉Cloudflare,当有人访问example.com/blog ,它应该。
- 拦截该请求(因为
example.com/blog并不真正存在)。 - 在幕后请求一个不同的域(
blog.example.com/blog),并 - 将最后一步的结果通过
example.com/blog传递给被屏蔽的访问者。
好吧,让我们更详细地了解一下!
第1步:使用Cloudflare
同样,我们使用Cloudflare的DNS。将你的域名的DNS指向那里是开始的第一步。
使用Cloudflare的原因是,它允许我们创建工人,能够在有人访问某些URL(称为Routes,我们将在第3步创建)时运行一些代码。这段代码将负责在幕后切换网站。
Cloudflare有一个很好的入门指南。目标是将您的域名--无论它在哪里注册--指向Cloudflare的名称服务器,并确认Cloudflare已在您的Cloudflare账户中连接。
第2步:创建工作程序
这段代码将负责在幕后切换网站。前往Workers,点击创建一个服务。

注意CPU时间的中位数!这个过程给请求增加了大约.7ms (所以基本上没有什么)。
命名你的服务,然后选择 "HTTP处理器"。

点击创建服务,然后快速编辑。

粘贴以下代码,在第16行用你自己的域名替换。
// Listen for every request and respond with our function.
// Note, this will only run on the routes configured in Cloudflare.
addEventListener('fetch', function(event) {
event.respondWith(handleRequest(event.request))
})
// Our function to handle the response.
async function handleRequest(request) {
// Only GET requests work with this proxy.
if (request.method !== 'GET')
return MethodNotAllowed(request);
// The URL that is being requested.
const url = new URL(request.url);
// Request "origin URL" aka the real blog instead of what was requested.
// This switches out the absolute URL leaving the relative path unchanged.
const originUrl = url.toString().replace('https://example.com', 'https://blog.example.com');
// The contents of the origin page.
const originPage = await fetch(originUrl);
// Give the response our origin page.
const newResponse = new Response(originPage.body, originPage); return newResponse;
}
// Hey! GET requests only
function MethodNotAllowed(request) {
return new Response(`Method ${request.method} not allowed.`, {
status: 405,
headers: { 'Allow': 'GET' }
})
}
最后,点击保存和部署。
第3步:添加路由
现在,让我们通知Cloudflare哪些URL(又称路由)要运行这段代码。前往Cloudflare中的网站,然后点击Workers。
在Cloudflare的主屏幕上有Workers部分,你在那里编辑代码,然后在每个网站上有Workers部分,你在那里添加路由。它们是两个不同的地方,让人很困惑。
首先,点击添加路线。

因为我们正在添加一个有许多子页面的博客,我们将使用https://example.com/blog* 。注意星号作为通配符用于匹配。这段代码将在博客页面和每个以blog 开始的页面上运行。
这可能会产生意想不到的后果。例如,你有一个以 "blog "开头的页面,但并不是真正的博客的一部分,如https://example.com/blogging-services 。这将被这一规则所识别。
然后,在 "服务"下拉菜单中选择 "工人"。
我们已经完成了很多工作,但还有更多的路线需要添加--CSS、JavaScript和其他博客依赖的文件路径(除非所有文件都托管在不同的URL上,比如CDN上)。找到这些的一个好方法是通过测试你的路由和检查控制台。
前往你的https://example.com/blog ,确保有东西正在加载。它看起来会很混乱,因为它缺少主题文件。这对现在来说很好,只要它不产生404错误就可以了。重要的是打开你的浏览器的DevTools,启动控制台,记下所有它找不到或加载的红色URL(通常是404或403),它们是你的域名的一部分。

橙色框中的资源是我们需要的目标。
你要把这些资源作为路由添加......但只做父路径。因此,如果你的红色URL是https://example.com/wp-content/themes/file1.css ,那么就把https://example.com/wp-content* 作为你的路径。如果你想更具体一些,你也可以添加一个子路径,但我们的想法是用一个路由来捕捉大部分的文件。

一旦你添加了这些路由,检查你的URL,看看它是否看起来像你的子域。如果不是,请检查前面的步骤。(有可能你将需要添加更多的路由)。
最好是通过浏览多个页面来做质量检查,看看是否有什么遗漏。我还建议打开DevTools,搜索你的子域(blog.example.com)。如果显示出来了,你要么需要添加路由来针对这些资源**,要么**对你的平台做一些事情来停止输出这些URL。例如,我的平台输出的是我的子域名的规范标签,所以我找到了一个插件来修改规范的URL,使其成为我的根域。
第四步:最秘密的酱料 (noindex)
你可能会发现,我们有一个问题。我们的URL在两个不同的URL上可用。是的,我们可以使用canonical 属性来通知谷歌哪个URL是我们的 "主",但我们不要让谷歌来选择正确的URL。
首先,将你的整个子域设置为noindex(这样做的方法将因平台而异)。然后,在Cloudflare Worker中,我们要添加以下一行代码,这基本上是说,当通过代理访问当前URL时,要删除noindex 。
newResponse.headers.delete("x-robots-tag");
完整的代码解决方案将在本文末尾提供。
第5步:修改网站地图
最后要做的是修改子域的网站地图,使其不在其中使用子域。这样做的方法因平台而异,但目标是修改网站地图中的基数/绝对数/域名,使其打印出example.com/mypost),而不是blog.exmaple.com/mypost 。有些插件和模块会允许这样做,而不需要自定义代码。
就这样了!该解决方案应该可以使用了!
限制因素
这种Cloudflare魔法并非没有缺点。例如,它只接受GET 请求,这意味着我们只能从服务器上获取东西。我们无法POST ,而这正是表单的用途。因此,如果你需要让你的访问者登录或提交表单,在我们已经完成的工作之外,还会有更多的工作。我在另一篇文章中讨论了这方面的几个解决方案。
如前所述,另一个限制是,在Shopify上使用这种方法需要订阅Cloudflare的企业定价层。同样,这是因为Shopify也使用Cloudflare,并限制了他们其他计划中的流量代理能力。
如果你试图将两个相同平台的实例合并在一起,你也可能会遇到一些问题(例如,你的顶级域名和子域名都使用WordPress)。但在这样的情况下,你应该能够合并并使用一个平台的实例。
完整的解决方案
下面是代码的全部内容。
// Listen for every request and respond with our function.
// Note, this will only run on the routes configured in Cloudflare.
addEventListener('fetch', function(event) {
event.respondWith(handleRequest(event.request))
})
// Our function to handle the response.
async function handleRequest(request) {
// Only GET requests work with this proxy.
if (request.method !== 'GET') return MethodNotAllowed(request);
// The URL that is being requested.
const url = new URL(request.url);
// Request "origin URL" aka the real blog instead of what was requested.
// This switches out the absolute URL leaving the relative path unchanged.
const originUrl = url.toString().replace('https://example.com', 'https://blog.example.com');
// The contents of the origin page.
const originPage = await fetch(originUrl);
// Give the response our origin page.
const newResponse = new Response(originPage.body, originPage);
// Remove "noindex" from the origin domain.
newResponse.headers.delete("x-robots-tag");
// Remove Cloudflare cache as it's meant for WordPress.
// If you are using Cloudflare APO and your blog isn't WordPress, (but
// your main domain is), then stop APO from running on your origin URL.
// newResponse.headers.set("cf-edge-cache", "no-cache"); return newResponse;
}
// Hey! GET requests only
function MethodNotAllowed(request) {
return new Response(`Method ${request.method} not allowed.`, {
status: 405,
headers:
{ 'Allow': 'GET' }
})
}