Next.js 14中如何组合Supabase与next-intl中间件?
在Next.js中整合Supabase与next-intl中间件的问题
我在NextJS应用里集成Supabase(参考文档第4点)和next-intl时碰到了麻烦——这两个库的中间件都会直接返回NextResponse,我尝试同时使用它们,但始终没法合并返回同一个NextResponse。
我试过用stackMiddlewares自定义中间件,但这两个中间件都不返回NextResponse,只返回NextMiddleware。
我已经写了两个中间件:
export const withI18n: MiddlewareFactory = (next) => { return async (request: NextRequest, _next: NextFetchEvent) => { // 该如何处理这个? const response = createMiddleware({ defaultLocale: 'en', locales: SUPPORTED_LOCALES, pathnames, localePrefix, }); return next(request, _next); }; };
以及参考Supabase客户端文档实现的updateSession方法对应的中间件:
export const withSupabaseSessionUpdate: MiddlewareFactory = (next) => { return async (request: NextRequest, _next: NextFetchEvent) => { // 该如何处理这个? const response = await updateSession(request); return next(request, _next); }; };
解决方案
核心思路是让两个中间件链式处理请求和响应——先让一个中间件生成响应,再把这个响应传给下一个中间件处理,最终返回经过两次处理的响应。
步骤1:修正中间件写法,支持响应传递
修正withI18n中间件
createMiddleware返回的是Middleware函数,需要用它处理当前请求拿到响应,再传给后续中间件:
export const withI18n: MiddlewareFactory = (next) => { return async (request: NextRequest, event: NextFetchEvent) => { // 调用next-intl中间件处理请求,得到初始响应 const i18nMiddleware = createMiddleware({ defaultLocale: 'en', locales: SUPPORTED_LOCALES, pathnames, localePrefix, }); const response = await i18nMiddleware(request, event); // 将响应传给下一个中间件 return next(request, event, response); }; };
修正withSupabaseSessionUpdate中间件
updateSession需要接收请求和已有响应,更新后再传递或返回:
export const withSupabaseSessionUpdate: MiddlewareFactory = (next) => { return async (request: NextRequest, event: NextFetchEvent, prevResponse?: NextResponse) => { // 若无前置响应,创建默认响应 const baseResponse = prevResponse || NextResponse.next(); // 基于现有响应更新Supabase会话 const updatedResponse = await updateSession(request, baseResponse); // 有后续中间件则传递响应,否则直接返回 return next ? next(request, event, updatedResponse) : updatedResponse; }; };
步骤2:扩展MiddlewareFactory类型
让类型支持传递前置响应:
type MiddlewareFactory = ( next: (request: NextRequest, event: NextFetchEvent, response?: NextResponse) => Promise<NextResponse> ) => (request: NextRequest, event: NextFetchEvent, response?: NextResponse) => Promise<NextResponse>;
步骤3:实现中间件堆叠函数
用reduceRight实现中间件链式调用:
export const stackMiddlewares = (middlewares: MiddlewareFactory[]) => { return middlewares.reduceRight( (next, middleware) => middleware(next), async (req, evt, res) => res || NextResponse.next() ); };
步骤4:整合中间件
在middleware.ts中挂载堆叠后的中间件:
export default stackMiddlewares([withSupabaseSessionUpdate, withI18n]); // 配置中间件匹配路径(按需调整) export const config = { matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'], };
关键注意点
- 执行顺序:若需先处理国际化路由再更新会话,调整数组顺序为
[withI18n, withSupabaseSessionUpdate]即可 - 每个中间件必须接收前置响应并返回处理后的新响应,确保两个库的逻辑作用于同一个
NextResponse
内容的提问来源于stack exchange,提问作者Rafał Prokopiak
相关产品推荐
相关产品推荐

