Skip to content

服务路由

server/routes/ 目录与 server/api/ 类似,但不带 /api 前缀,适合提供非 JSON API 的服务端功能。

与 API 路由的区别

特性server/api/server/routes/
URL 前缀/api//
典型用途REST API(数据接口)站点地图、RSS、健康检查
返回格式JSON(默认)任意格式(XML、文本、图片等)
路由参数✅ 支持✅ 支持
HTTP 方法✅ 支持✅ 支持

什么时候用 server/routes/

当你需要提供非 API 的服务端功能时:

  • SEO 相关文件:sitemap.xmlrobots.txt
  • 订阅源:RSS / Atom Feed
  • 运维:健康检查、版本信息
  • 动态图片:OG 图片生成

简单记忆

返回 JSON 数据 → server/api/;返回其他格式 → server/routes/

基本用法

ts
// server/routes/sitemap.ts → /sitemap
export default defineEventHandler(() => {
  const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
    <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
      <url><loc>https://example.com/</loc></url>
    </urlset>`
  setResponseHeader(event, 'content-type', 'text/xml')
  return sitemap
})

路由文件的 URL 映射规则

  • server/routes/sitemap.ts/sitemap
  • server/routes/sitemap.xml.ts/sitemap.xml
  • server/routes/feed.xml.ts/feed.xml
  • server/routes/blog/[slug].ts/blog/:slug

文件名中包含扩展名

(如 sitemap.xml.ts)可以生成带扩展名的 URL(如 /sitemap.xml)。

常见用途

sitemap.xml

ts
// server/routes/sitemap.xml.ts → /sitemap.xml
export default defineEventHandler(async (event) => {
  // 动态获取文章列表
  const posts = await $fetch('/api/posts')

  setResponseHeader(event, 'content-type', 'text/xml')
  return `<?xml version="1.0" encoding="UTF-8"?>
    <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
      <url>
        <loc>https://example.com/</loc>
        <changefreq>daily</changefreq>
        <priority>1.0</priority>
      </url>
      ${posts.map((post: any) => `
        <url>
          <loc>https://example.com/blog/${post.slug}</loc>
          <lastmod>${post.updatedAt}</lastmod>
          <priority>0.8</priority>
        </url>
      `).join('')}
    </urlset>`
})

SEO 提示

sitemap.xml 帮助搜索引擎发现和索引你的页面。推荐动态生成,确保搜索引擎始终能发现新内容。

robots.txt

ts
// server/routes/robots.txt.ts → /robots.txt
export default defineEventHandler((event) => {
  const config = useRuntimeConfig()

  setResponseHeader(event, 'content-type', 'text/plain')
  return `User-agent: *
Allow: /
Disallow: /admin/
Disallow: /api/
Sitemap: ${config.public.siteUrl}/sitemap.xml`
})

动态 robots.txt 的好处

可以根据环境变量或配置动态生成,如开发环境禁止所有爬虫。

RSS Feed

ts
// server/routes/feed.xml.ts → /feed.xml
export default defineEventHandler(async (event) => {
  const posts = await fetchRecentPosts()

  setResponseHeader(event, 'content-type', 'application/xml')
  return `<?xml version="1.0" encoding="UTF-8"?>
    <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
      <channel>
        <title>My Blog</title>
        <link>https://example.com</link>
        <description>最新文章</description>
        <atom:link href="https://example.com/feed.xml" rel="self" type="application/rss+xml"/>
        ${posts.map(post => `
          <item>
            <title>${escapeXml(post.title)}</title>
            <link>https://example.com/blog/${post.slug}</link>
            <guid isPermaLink="true">https://example.com/blog/${post.slug}</guid>
            <pubDate>${new Date(post.publishedAt).toUTCString()}</pubDate>
            <description>${escapeXml(post.excerpt)}</description>
          </item>
        `).join('')}
      </channel>
    </rss>`
})

INFO

XML 中的特殊字符:RSS 内容中的 <>& 等字符需要转义 否则 XML 解析会失败。使用 escapeXml() 函数处理

健康检查

ts
// server/routes/health.ts → /health
export default defineEventHandler(() => {
  return {
    status: 'ok',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    memory: process.memoryUsage(),
    version: useRuntimeConfig().public.version,
  }
})

健康检查的作用

负载均衡器(如 Nginx、AWS ALB)和监控系统通过访问 /health 来检测服务是否正常运行。如果返回 200,说明服务健康。

OG 图片生成

ts
// server/routes/og.png.ts → /og.png
export default defineEventHandler(async (event) => {
  const title = getQuery(event).title as string

  // 使用 Satori 生成 OG 图片
  const svg = await generateOGImage({ title })

  setResponseHeader(event, 'content-type', 'image/png')
  // 将 SVG 转为 PNG
  return await sharp(Buffer.from(svg)).png().toBuffer()
})

OG 图片

社交媒体(微信、Twitter、Facebook)分享链接时显示的预览图片。推荐使用 Satori 将 JSX/HTML 转为 SVG,再转为 PNG。

动态服务路由

与 API 路由一样支持动态参数:

ts
// server/routes/blog/[slug].ts → /blog/my-post
export default defineEventHandler((event) => {
  const slug = getRouterParam(event, 'slug')
  return { slug }
})

// server/routes/users/[id].ts → /users/123
export default defineEventHandler((event) => {
  const id = getRouterParam(event, 'id')
  return { id }
})

// 匹配所有子路由
// server/routes/docs/[...slug].ts → /docs/a/b/c
export default defineEventHandler((event) => {
  const slug = getRouterParam(event, 'slug')
  // slug = 'a/b/c'
  return { slug }
})

HTTP 方法路由

与 API 路由一样支持按 HTTP 方法定义:

ts
// server/routes/contact.ts
export default defineEventHandler((event) => {
  // 根据方法分发
  if (event.method === 'GET') {
    return { message: 'Contact form' }
  }

  if (event.method === 'POST') {
    // 处理表单提交
    return { success: true }
  }
})

服务路由通常只处理 GET 请求

(提供静态文件内容)。如果需要处理 POST 等方法,推荐使用 server/api/

知识脉络

text
API 路由 → 你在这里:服务路由

              ├─→ 下一步:服务中间件

              └─→ 相关:SEO 与元数据 → 链接预取(sitemap / robots)

基于 Nuxt 4 官方文档整理编写