You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

部署在Vercel的Next.js项目:如何实现可复用的API跨域中间件?

当然可以,下面提供两种高效的统一处理CORS的方案,无需在每个API路由中重复编写跨域逻辑:

方案一:使用Next.js Middleware(middleware.ts)

Next.js 12及以上版本支持Middleware,可全局拦截API路由请求并统一配置CORS规则,适合批量处理所有API接口的跨域需求。

在项目根目录创建middleware.ts文件,编写以下代码:

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  // 仅对/api/开头的路由应用CORS处理
  if (request.nextUrl.pathname.startsWith('/api/')) {
    // 单独处理OPTIONS预请求
    if (request.method === 'OPTIONS') {
      return new NextResponse(null, {
        status: 200,
        headers: {
          'Access-Control-Allow-Credentials': 'true',
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
          'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, Authorization',
        },
      })
    }

    // 对其他API请求统一设置CORS响应头
    const response = NextResponse.next()
    response.headers.set('Access-Control-Allow-Credentials', 'true')
    response.headers.set('Access-Control-Allow-Origin', '*')
    response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
    response.headers.set('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization')
    return response
  }

  // 非API路由直接放行
  return NextResponse.next()
}

// 配置路由匹配规则,仅作用于所有API子路由
export const config = {
  matcher: '/api/:path*',
}

关键说明

  • 通过matcher精准锁定API路由,避免影响页面渲染逻辑
  • 自动拦截并响应OPTIONS预请求,无需在每个handler中重复处理
  • 如果需要更严格的跨域控制(比如限制特定域名),可以将Access-Control-Allow-Origin改为动态值:
    const allowedOrigins = ['https://your-domain.com', 'http://localhost:3000']
    const origin = request.headers.get('origin')
    const allowedOrigin = allowedOrigins.includes(origin || '') ? origin : '*'
    response.headers.set('Access-Control-Allow-Origin', allowedOrigin)
    
方案二:使用包装函数封装API Handler

如果不想使用Middleware,可以通过高阶函数封装CORS逻辑,在每个API路由中复用,适合灵活调整单个接口的跨域规则。

  1. 创建工具函数文件utils/corsHandler.ts:
import type { NextApiRequest, NextApiResponse } from 'next'

// 定义API handler的类型
type ApiHandler = (req: NextApiRequest, res: NextApiResponse) => Promise<void> | void

export function withCors(handler: ApiHandler) {
  return async (req: NextApiRequest, res: NextApiResponse) => {
    // 统一设置CORS头
    res.setHeader('Access-Control-Allow-Credentials', 'true')
    res.setHeader('Access-Control-Allow-Origin', '*')
    res.setHeader('Access-Control-Allow-Methods', 'GET')
    res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization')

    // 处理OPTIONS预请求
    if (req.method === 'OPTIONS') {
      res.status(200).end()
      return
    }

    // 执行原API业务逻辑
    await handler(req, res)
  }
}
  1. 在API路由中使用包装函数:
import type { NextApiRequest, NextApiResponse } from 'next'
import { withCors } from '../../utils/corsHandler'

type House = {
  house: string
  price: number
  timestamp: string
  developer: string
}

// 仅保留核心业务逻辑
async function houseHandler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  let houses: House[] = []

  try {
    await client.connect()
    console.log('Connected to MongoDB')

    const db = client.db('vroom')
    const housesCollection = db.collection('houses')

    houses = (await housesCollection.find().toArray()).map((house) => ({
      house: house.house,
      price: house.price,
      timestamp: house.timestamp,
      developer: house.developer,
    }))

    console.log('Retrieved houses:', houses)
  } catch (error) {
    console.error(`Error connecting to MongoDB: ${error}`)
  } finally {
    await client.close()
  }

  res.json({ houses })
}

// 用withCors包装原handler
export default withCors(houseHandler)

关键说明

  • 把CORS逻辑完全抽离,原handler只需专注业务实现
  • 可根据不同接口需求,修改withCors中的头配置(比如给特定接口开放POST方法)

内容的提问来源于stack exchange,提问作者Cal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 12:35:08