mcpField
R
route-handlers

route-handlers

github.com/davepoon开发3.7k145 次安装今天更新
代码仓库

关于 route-handlers

route-handlers 是面向 Next.js 开发者的 API 端点参考技能,介绍请求与响应处理、HTTP 方法、流式响应、缓存和错误处理模式。

主要功能

  1. 01使用 route.ts 文件定义端点
  2. 02处理 HTTP 方法和请求数据
  3. 03返回 JSON、重定向和流式响应
  4. 04配置标头、Cookie、CORS 和缓存

适用场景

  1. 01创建 CRUD API 端点
  2. 02读取查询参数和动态路由值
  3. 03流式传输文本或 LLM 响应

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/davepoon/buildwithclaude --skill route-handlers

安装后在 Claude Code 中输入/route-handlers确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

examples/
crud-api.md
references/
http-methods.md
streaming-responses.md

详细介绍

Next.js 路由处理程序

概述

路由处理程序允许你使用 Web Request 和 Response API 创建 API 端点。它们定义在 app 目录中的 route.ts 文件里。

基本结构

文件约定

路由处理程序使用 route.ts(或 route.js):

app/
├── api/
│   ├── users/
│   │   └── route.ts      # /api/users
│   └── posts/
│       ├── route.ts      # /api/posts
│       └── [id]/
│           └── route.ts  # /api/posts/:id
HTTP 方法

导出以 HTTP 方法命名的函数:

// app/api/users/route.ts
import { NextResponse } from 'next/server'

export async function GET() {
  const users = await db.user.findMany()
  return NextResponse.json(users)
}

export async function POST(request: Request) {
  const body = await request.json()
  const user = await db.user.create({ data: body })
  return NextResponse.json(user, { status: 201 })
}

支持的方法:GET、POST、PUT、PATCH、DELETE、HEAD、OPTIONS

请求处理

读取请求正文
export async function POST(request: Request) {
  // JSON body
  const json = await request.json()

  // Form data
  const formData = await request.formData()
  const name = formData.get('name')

  // Text body
  const text = await request.text()

  return NextResponse.json({ received: true })
}
URL 参数

动态路由参数:

// app/api/posts/[id]/route.ts
interface RouteContext {
  params: Promise<{ id: string }>
}

export async function GET(
  request: Request,
  context: RouteContext
) {
  const { id } = await context.params
  const post = await db.post.findUnique({ where: { id } })

  if (!post) {
    return NextResponse.json(
      { error: 'Not found' },
      { status: 404 }
    )
  }

  return NextResponse.json(post)
}
查询参数
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url)
  const page = searchParams.get('page') ?? '1'
  const limit = searchParams.get('limit') ?? '10'

  const posts = await db.post.findMany({
    skip: (parseInt(page) - 1) * parseInt(limit),
    take: parseInt(limit),
  })

  return NextResponse.json(posts)
}
请求标头
export async function GET(request: Request) {
  const authHeader = request.headers.get('authorization')

  if (!authHeader?.startsWith('Bearer ')) {
    return NextResponse.json(
      { error: 'Unauthorized' },
      { status: 401 }
    )
  }

  const token = authHeader.split(' ')[1]
  // Validate token...

  return NextResponse.json({ authenticated: true })
}

响应处理

JSON 响应
import { NextResponse } from 'next/server'

export async function GET() {
  return NextResponse.json(
    { message: 'Hello' },
    { status: 200 }
  )
}
设置标头
export async function GET() {
  return NextResponse.json(
    { data: 'value' },
    {
      headers: {
        'Cache-Control': 'max-age=3600',
        'X-Custom-Header': 'custom-value',
      },
    }
  )
}
设置 Cookie
import { cookies } from 'next/headers'

export async function POST(request: Request) {
  const cookieStore = await cookies()

  // Set cookie
  cookieStore.set('session', 'abc123', {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
    maxAge: 60 * 60 * 24 * 7, // 1 week
  })

  return NextResponse.json({ success: true })
}
重定向
import { redirect } from 'next/navigation'
import { NextResponse } from 'next/server'

export async function GET() {
  // Option 1: redirect function (throws)
  redirect('/login')

  // Option 2: NextResponse.redirect
  return NextResponse.redirect(new URL('/login', request.url))
}

流式响应

文本流式传输
export async function GET() {
  const encoder = new TextEncoder()
  const stream = new ReadableStream({
    async start(controller) {
      for (let i = 0; i < 10; i++) {
        controller.enqueue(encoder.encode(`data: ${i}\n\n`))
        await new Promise(resolve => setTimeout(resolve, 100))
      }
      controller.close()
    },
  })

  return new Response(stream, {
    headers: {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive',
    },
  })
}
AI/大模型流式传输
export async function POST(request: Request) {
  const { prompt } = await request.json()

  const response = await openai.chat.completions.create({
    model: 'gpt-4',
    messages: [{ role: 'user', content: prompt }],
    stream: true,
  })

  const stream = new ReadableStream({
    async start(controller) {
      for await (const chunk of response) {
        const text = chunk.choices[0]?.delta?.content || ''
        controller.enqueue(new TextEncoder().encode(text))
      }
      controller.close()
    },
  })

  return new Response(stream, {
    headers: { 'Content-Type': 'text/plain' },
  })
}

CORS 配置

export async function OPTIONS() {
  return new Response(null, {
    status: 204,
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
      'Access-Control-Allow-Headers': 'Content-Type, Authorization',
    },
  })
}

export async function GET() {
  return NextResponse.json(
    { data: 'value' },
    {
      headers: {
        'Access-Control-Allow-Origin': '*',
      },
    }
  )
}

缓存

静态(GET 的默认行为)
// Cached by default
export async function GET() {
  const data = await fetch('https://api.example.com/data')
  return NextResponse.json(await data.json())
}
禁用缓存
export const dynamic = 'force-dynamic'

export async function GET() {
  // Always fresh
}

// Or use cookies/headers (auto opts out)
import { cookies } from 'next/headers'

export async function GET() {
  const cookieStore = await cookies()
  // Now dynamic
}

错误处理

export async function GET(request: Request) {
  try {
    const data = await riskyOperation()
    return NextResponse.json(data)
  } catch (error) {
    console.error('API Error:', error)

    if (error instanceof ValidationError) {
      return NextResponse.json(
        { error: error.message },
        { status: 400 }
      )
    }

    return NextResponse.json(
      { error: 'Internal Server Error' },
      { status: 500 }
    )
  }
}

资源

如需了解详细模式,请参阅:

  • references/http-methods.md - 完整的 HTTP 方法指南
  • references/streaming-responses.md - 高级流式传输模式
  • examples/crud-api.md - 完整的 CRUD API 示例

评论

支持 Markdown