部署在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路由中复用,适合灵活调整单个接口的跨域规则。
- 创建工具函数文件
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) } }
- 在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
相关产品推荐
相关产品推荐

