Jamdesk Documentation logo

Vercel

了解如何通过 vercel.json 重写或 Edge Middleware,将 Jamdesk 文档部署到 Vercel 域名的 /docs 路径。

如果您的网站部署在 Vercel 上,可以通过自己的域名在 /docs 提供 Jamdesk 文档。有两种设置方式,最终结果相同:

前提条件

  • 一个部署在 Vercel 上的项目
  • 您的 Jamdesk 子域名(可在仪表板设置中找到),并已启用 Host at a subpath
  • 已在仪表板中注册并验证的自定义域名

选项 A:vercel.json 重写

如果您使用的是自定义子路径而不是默认的 /docs,请将以下代码片段中的每个 /docs 替换为您的子路径,包括每条规则的 sourcedestination。在仪表板中重命名后重新部署;系统不会为您重新生成此文件。

重写可以更改请求的去向,但无法添加请求标头,因此每个目标地址都会携带一个公开标记 ?jd_proxy=1,用于告知 Jamdesk 请求经过了您的代理。Jamdesk 会在渲染前移除该标记,访问者不会看到它。

在项目根目录中创建或编辑 vercel.json,将 YOUR_SLUG 替换为您的 Jamdesk 子域名:

vercel.json
{
  "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

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.txtsitemap.xmlllms.txtllms-full.txt 位于域名根目录,不在 /docs 下;没有这些文件,搜索引擎和 AI 代理就无法发现您的文档。如果 Jamdesk 管理您的域名根目录,请再添加四条规则:

vercel.json
{
  "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.txtsitemap.xml,请将两者合并,而不是用其中一个覆盖另一个。

部署并验证

使用 vercel --prod 部署(或推送到已连接的 Git 仓库),然后打开 https://yoursite.com/docs 并查看页面源代码。检查以下两项:

  1. <link rel="canonical"> 指向 您的域名,而不是 YOUR_SLUG.jamdesk.app
  2. 不存在 <meta name="robots" content="noindex">

如果其中任何一项不正确,说明某条重写缺少 ?jd_proxy=1 标记 — 请参阅标记为何重要

选项 B:Edge Middleware

如果您已经在运行 Edge Middleware,可以在那里设置 X-Jamdesk-Forwarded-Host 请求标头,而不是使用标记。这两个信号是等效的;仅当您希望将路由逻辑保留在已经维护的代码中时,才选择此选项。

在项目根目录中创建 middleware.ts 文件,将 YOUR_SLUG 替换为您的 Jamdesk 子域名:

middleware.ts
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:

vercel.json
{
  "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.txtsitemap.xml,请进行合并。

部署并验证

使用 vercel --prod 部署(或推送到已连接的 Git 仓库),然后打开 https://yoursite.com/docs 并查看页面源代码。检查以下两项:

  1. <link rel="canonical"> 指向 您的域名,而不是 YOUR_SLUG.jamdesk.app
  2. 不存在 <meta name="robots" content="noindex">

如果其中任何一项不正确,说明 X-Jamdesk-Forwarded-Host 标头没有到达 Jamdesk — 请确认 matcher 中包含 /docs

为什么需要标记

Jamdesk 需要一个信号,用于确认请求是通过您的代理到达的,而不是直接访问您的 *.jamdesk.app 子域名。?jd_proxy=1 标记和 X-Jamdesk-Forwarded-Host 标头都能传递该信号,Jamdesk 将二者视为等效。任一信号都会确认您注册的域名,将规范链接、Open Graph 和 sitemap 链接指向该域名,并允许仅限自定义域名区分代理流量和直接访问。

缺少信号时不会明确报错 — 页面仍会渲染,但如果未注册自定义域名,会带有 noindex 和指向子域名的规范链接;如果已注册自定义域名,则仅限自定义域名检查会失败。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,请确认 Middleware matcher 中包含 /docs — 仅使用 vercel.json 重写无法设置标头。

标记或标头已到达 Jamdesk,但其中指定的域名不是 Jamdesk 为此项目提供服务的域名:

  1. 确认您的域名已在 Jamdesk 仪表板中注册
  2. 完成 DNS 验证(TXT 记录)
  3. 检查域名是否映射到正确的项目,并标记为已激活
  4. 对于选项 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)。请参阅仅限自定义域名

接下来呢?

仅限自定义域名

停止子域名直接响应请求

自定义域名

验证 DNS 并排查问题

子路径托管

在 /docs 提供文档