Vercel
了解在 Vercel 部署的域名 /docs 路径下提供 Jamdesk 文档的两种方式:vercel.json 重写或 Edge Middleware。
在你 Vercel 部署的域名上的 /docs 路径下提供 Jamdesk 文档。选择以下两种设置之一,效果相同。
- 方案 A:vercel.json 重写:无需代码,适用于任何框架。从这里开始。
- 方案 B:Edge Middleware:适用于已经在使用 Edge Middleware、希望将 Jamdesk 配置放在同一文件中的站点。
前提条件
- 已部署在 Vercel 上的项目
- 你的 Jamdesk 子域名(可在仪表板设置中找到),并已启用 Host at a subpath
- 已在仪表板中注册并验证的自定义域名
选项 A:vercel.json 重写
使用自定义子路径而非默认的 /docs?请将下方代码片段中每条规则的 source 和 destination 里的 /docs 替换为你的子路径。在仪表板中重命名子路径后重新部署。此文件不会为你自动生成。
重写可以改变请求的去向,但无法添加请求头。因此每个目标地址都带有一个公开标记 ?jd_proxy=1,它告诉 Jamdesk 该请求经过了你的代理。Jamdesk 在渲染前会将其移除,访问者不会看到它。
在项目根目录创建或编辑 vercel.json,将 YOUR_SLUG 替换为你的 Jamdesk 子域名:
{
"rewrites": [
{ "source": "/docs", "destination": "https://YOUR_SLUG.jamdesk.app/docs?jd_proxy=1" },
{ "source": "/docs/:path*", "destination": "https://YOUR_SLUG.jamdesk.app/docs/:path*?jd_proxy=1" },
{ "source": "/_next/:path*", "destination": "https://YOUR_SLUG.jamdesk.app/_next/:path*" },
{ "source": "/_jd/:path*", "destination": "https://YOUR_SLUG.jamdesk.app/_jd/:path*?jd_proxy=1" }
]
}/_next/:path* 不需要标记。它是 Jamdesk 从不拦截的静态资源路径。非 Next.js 站点本身没有 /_next/ 文件,该路径下的所有请求都会转发给 Jamdesk。
对于 Next.js 项目,同样的四条规则也可写在 next.config.js 中:
/** @type {import('next').NextConfig} */
const nextConfig = {
async rewrites() {
return [
{ source: "/docs", destination: "https://YOUR_SLUG.jamdesk.app/docs?jd_proxy=1" },
{ source: "/docs/:path*", destination: "https://YOUR_SLUG.jamdesk.app/docs/:path*?jd_proxy=1" },
{ source: "/_next/:path*", destination: "https://YOUR_SLUG.jamdesk.app/_next/:path*" },
{ source: "/_jd/:path*", destination: "https://YOUR_SLUG.jamdesk.app/_jd/:path*?jd_proxy=1" },
];
},
};
export default nextConfig;同时转发根目录文件
robots.txt、sitemap.xml、llms.txt 和 llms-full.txt 位于域名根目录,不在 /docs 下。搜索引擎和 AI 代理需要它们来发现你的文档。如果域名根目录由 Jamdesk 托管,请再添加四条规则:
{
"rewrites": [
{ "source": "/robots.txt", "destination": "https://YOUR_SLUG.jamdesk.app/robots.txt?jd_proxy=1" },
{ "source": "/sitemap.xml", "destination": "https://YOUR_SLUG.jamdesk.app/sitemap.xml?jd_proxy=1" },
{ "source": "/llms.txt", "destination": "https://YOUR_SLUG.jamdesk.app/llms.txt?jd_proxy=1" },
{ "source": "/llms-full.txt", "destination": "https://YOUR_SLUG.jamdesk.app/llms-full.txt?jd_proxy=1" }
]
}如果你的营销站点已在根目录提供自己的 robots.txt 或 sitemap.xml,请合并两者,而不是用其中一个覆盖另一个。
部署并验证
使用 vercel --prod 部署(或推送到已连接的 Git 仓库)。打开 https://yoursite.com/docs 并查看页面源代码,检查两点:
<link rel="canonical">指向你的域名,而非YOUR_SLUG.jamdesk.app- 不存在
<meta name="robots" content="noindex">
如果其中任一项不正确,说明某条重写缺少 ?jd_proxy=1 标记。参见为什么标记很重要。
选项 B:Edge Middleware
在 Edge Middleware 中设置 X-Jamdesk-Forwarded-Host 请求头,代替使用标记。两种信号效果等同。若希望将路由逻辑保留在你已维护的代码中,请选择此方案。
在项目根目录创建 middleware.ts 文件,将 YOUR_SLUG 替换为你的 Jamdesk 子域名:
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
const JAMDESK_HOST = 'YOUR_SLUG.jamdesk.app';
export function middleware(request: NextRequest) {
const url = request.nextUrl;
const destination = new URL(url.pathname + url.search, `https://${JAMDESK_HOST}`);
// Clone headers and tell Jamdesk which domain the visitor actually used.
const headers = new Headers(request.headers);
headers.set('X-Jamdesk-Forwarded-Host', url.hostname);
return NextResponse.rewrite(destination, {
request: { headers },
});
}
export const config = {
matcher: ['/docs', '/docs/:path*', '/_jd/:path*'],
};若使用自定义子路径,请将上方 matcher 中的 /docs 和 /docs/:path* 替换为你配置的子路径。
不要将 /_next/:path* 添加到 matcher 中。 Middleware 在 Vercel 的文件系统检查之前运行。匹配 /_next/ 会将你自己站点的 JavaScript 和 CSS 发送给 Jamdesk,从而破坏样式。下一步会以安全的方式路由 /_next/。
将文件命名为 middleware.ts,并导出一个名为 middleware 的函数。Next.js 16 建议将其重命名为 proxy.ts,但 Vercel 生产环境目前不会调用 proxy.ts,重命名会静默地使其失效。
在 vercel.json 中路由资源和根目录文件
Jamdesk 页面从 /_next/ 加载其代码包。robots.txt 等根目录文件位于上方 matcher 之外。请用重写规则路由这两类文件。重写在文件系统检查之后运行,因此你自己的构建产物优先,只有你的站点无法提供的请求才会转发给 Jamdesk:
{
"rewrites": [
{ "source": "/_next/:path*", "destination": "https://YOUR_SLUG.jamdesk.app/_next/:path*" },
{ "source": "/robots.txt", "destination": "https://YOUR_SLUG.jamdesk.app/robots.txt?jd_proxy=1" },
{ "source": "/sitemap.xml", "destination": "https://YOUR_SLUG.jamdesk.app/sitemap.xml?jd_proxy=1" },
{ "source": "/llms.txt", "destination": "https://YOUR_SLUG.jamdesk.app/llms.txt?jd_proxy=1" },
{ "source": "/llms-full.txt", "destination": "https://YOUR_SLUG.jamdesk.app/llms-full.txt?jd_proxy=1" }
]
}根目录文件的目标地址带有 ?jd_proxy=1。Middleware 不会对它们运行,且重写无法设置请求头。仅当 Jamdesk 托管你的域名根目录时才需添加这些规则。如果你的站点提供自己的 robots.txt 或 sitemap.xml,请改为合并。
部署并验证
使用 vercel --prod 部署(或推送到已连接的 Git 仓库)。打开 https://yoursite.com/docs 并查看页面源代码,检查两点:
<link rel="canonical">指向你的域名,而非YOUR_SLUG.jamdesk.app- 不存在
<meta name="robots" content="noindex">
如果其中任一项不正确,说明 X-Jamdesk-Forwarded-Host 请求头未能到达 Jamdesk。请确认 /docs 已在 matcher 中。
为什么需要标记
Jamdesk 需要一个信号,以区分请求是经过你的代理到达的,还是直接访问你的 *.jamdesk.app 子域名。?jd_proxy=1 标记和 X-Jamdesk-Forwarded-Host 请求头承载了这一信号。Jamdesk 将两者视为等效。任一信号都会完成三件事:
- 确认你已注册的域名
- 将 canonical、Open Graph 和站点地图链接指向该域名
- 让仅自定义域名功能区分代理流量与直接访问
信号缺失时会悄然失败:页面仍能正常渲染。若未注册自定义域名,页面会带有 noindex 和子域名 canonical;若已注册自定义域名,"仅自定义域名"检查将失败。403 表示信号存在,但所指定的域名对该项目未注册或未激活。
故障排除
你的 matcher 很可能包含了 /_next/:path*。Middleware 在文件系统检查之前运行,会将你自己应用的资源路由到 Jamdesk。请从 matcher 中移除 /_next/,改为通过 vercel.json 路由。参见方案 B。
在 https://yoursite.com/docs 查看页面源代码。若存在 <meta name="robots" content="noindex"> 标签,说明标记和请求头都未到达 Jamdesk。在方案 A 中,确认每条重写的目标地址都以 ?jd_proxy=1 结尾(/_next/:path* 除外)。在方案 B 中,确认 /docs 已在 middleware matcher 中。仅靠 vercel.json 重写无法设置请求头。
标记或请求头已到达 Jamdesk,但所指定的域名不会为该项目提供服务:
- 确认你的域名已在 Jamdesk 仪表板中注册
- 完成 DNS 验证(TXT 记录)
- 检查该域名是否映射到正确的项目,且已标记为激活
- 在方案 B 中,确认 middleware 设置的请求头是访问者使用的域名,而非预览 URL
请确认你的重写(或 matcher)同时覆盖了 /docs 和 /docs/:path*。缺少通配符时,嵌套页面会失败。
请同时路由 /_jd/:path* 和 /_next/:path*。/_jd/ 提供 Jamdesk 字体、图片和品牌资源;/_next/ 提供文档代码包。缺少任一项都会破坏布局。
请检查文件是否位于项目根目录,且命名为 middleware.ts(而非 proxy.ts),并导出名为 middleware 的函数。Next.js 16 的弃用警告推荐使用 proxy.ts,但 Vercel 生产环境不会调用它。
请检查目标 URL 是否使用 https:// 并指向 jamdesk.app,而不是指回你自己的域名。
该检查会在你的正式域名上请求 /_jd/preflight,并检查到达 Jamdesk 的内容。“未标识自身”意味着某条重写到达 Jamdesk 时缺少标记或请求头。请重新检查每条重写的目标地址(方案 A)或你的 middleware 请求头(方案 B)。参见仅自定义域名。
