我有一个包含两个项目的单存储库 -web
和docs
.这些项目中的每一个都是他们自己的Vercel项目,web
项目安装在 https://example.com,docs
安装在 https://docs.example.com。 所有这些都按预期工作。
我现在想在 https://example.com/docs 上提供docs
项目。 在web
项目中,我在vercel.json
文件中设置了以下重写。
{
"rewrites": [
{
"source": "/docs/:match*",
"destination": "https://docs.example.com/:match*"
},
{ "source": "/(.*)", "destination": "/" }
]
}
这适用于主索引文件,但所有相应的 css 和 js 文件都会导致 404。浏览器正在查找这些文件,https://example.com/_next 这是不正确的,它应该查看 https://docs.example.com/_next。
我该如何完成这项工作?
rewrite
vs.redirect
让我们首先了解这种差异。
重写仅在服务器上发生。服务器将重写已请求的 URL,并搜索该重写 URL 的内容。客户对此一无所知。例如,如果/a.html 被重写为/b.html,则客户端将在两个 URL 上收到相同的内容。客户端不会知道是否有两次相同的文件,或者一个(或两个)请求是否已重写到其他资源。
另一方面,重定向涉及客户端(即浏览器)。如果要求服务器提供应重定向的 URL,它将使用重写的目标 URL 回复客户端/浏览器。然后,客户端将发送另一个新 URL 请求,并通过更改导航栏中的地址使其对最终用户可见。如果/a.html 重定向到/b.html,客户端在请求 a.html 时不会收到 b.html 的实际内容,但浏览器会将地址更新为 b.html 并发送新的请求。
在您的情况下重写有什么问题?
HTML 包含对使用绝对路径的其他资源的引用,例如:
<script src="/_next/static/..."></script>
如果此文件应作为docs.example.com
和example.com/docs
提供(例如使用重写),则实际的HTML不会更改。因此,浏览器将分别尝试访问docs.example.com/_next/static/...
或example.com/_next/static/...
。这适用于第一种情况(docs.example.com
),但不适用于第二种情况。你已经注意到了。
您可以更改 next 的basePath
,例如更改为/docs
。然后 HTML 将包含<script src="/docs/_next/...">
.这将使浏览器请求分别docs.example.com/docs/_next/...
或example.com/docs/_next/...
。这将适用于第二种情况,但不适用于第一种情况。你可以用更多的重写规则来治愈第一种情况,但我建议一个KISS解决方案。
现在怎么办?
如评论中所述,将完全相同的内容放在两个不同的地址不是好的做法。你可以看到,这也导致了随后的困难。(更不用说搜索引擎对重复内容的惩罚了。
一个好的解决方案是决定存储内容的位置。这应该是docs.example.com
或example.com/docs
,而不是两者兼而有之。
使用 docs.example.com,将 example.com/docs/转发到 docs.example.com
我建议(并在本节中假设)采取docs.example.com
来明确分离关注点。
所以在Vercel中,你将建立两个项目。一个用于您的"主"下一个实例,另一个用于"文档"下一个实例。(两者都可以来自同一个存储库,这无关紧要。
然后,您将域分配给两个项目,例如www.example.com
到"主"项目,docs.example.com
到"文档"项目。example.com
以及docs.example.com
现在应该在工作。example.com/docs/
应产生 404 错误。
然后,通过添加如下所示的vercel.json
,为您的"主"项目添加重定向(而不是重写!):
{
"redirects": [
{ "source": "/docs/:path*", "destination": "https://docs.example.com/:path*" }
]
}
现在,如果您在浏览器中输入example.com/docs/foo
,您应该被重定向到docs.example.com/foo
并且页面应该正确加载。
仅使用 example.com/docs/
如果您决定仅在example.com/docs/
上拥有文档内容,解决方案如下:
- 将
basePath: '/docs'
添加到next.config.js
文档下一个项目中。不要向此 vercel 项目添加域。 - 在"主要"下一个项目中添加一个
vercel.json
,如下所示:
{
"rewrites": [
{ "source": "/docs", "destination": "https://$domain-of-docs-project.vercel.app/docs" },
{ "source": "/docs/:path*", "destination": "https://$domain-of-docs-project.vercel.app/docs/:path*" }
]
}
如果您有其他问题或这不能解决问题,请发表评论。
我认为你可以像这样使用vercel.json:
{
"rewrites": [
{
"source": "/:path*",
"has": [
{
"type": "host",
"value": "docs.example.com"
}
],
"destination": "/docs/:path*"
}
]
}
Next 为此提供了一个具体的例子。
您的"Web"项目应该处理重写,如下所示。 next.config.js:
const { DOCS_URL } = process.env //this should be the vercel URL NOT docs.example.com
/** @type {import('next').NextConfig} */
module.exports = {
async rewrites() {
return [
{
source: '/:path*',
destination: `/:path*`,
},
{
source: '/docs',
destination: `${DOCS_URL}/docs`,
},
{
source: '/blog/:path*',
destination: `${BLOG_URL}/docs/:path*`,
},
]
},
}
您的"文档"应用需要设置基本路径,如下所示。 next.config.js:
module.exports = {
basePath: '/docs',
}
然后,为了确保 docs.example.com 不再为文档提供服务,我只需删除DNS记录。相反,您只需要一个vercel URL,您将在"web"中的重写中使用。无需从 docs.example.com 指向该服务器。
下一页 多可用区 js 文档
下一个具有多区域的 js 示例