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

Next.js 13链式调用认证与国际化中间件的类型错误问题

解决方案:修复Next.js 13多中间件链式调用的类型错误

你的类型错误根源在于中间件结构不符合链式函数要求的MiddlewareFactory类型:chain函数期望每个中间件是一个高阶函数(接收下一个中间件作为参数,返回新的中间件),但你当前的Internationalization和Authentication都是直接处理请求的普通中间件,导致类型不兼容。

以下是修正后的完整代码:

1. 修正authentication.ts

将Clerk认证中间件包装为符合MiddlewareFactory的结构,确保它能链式调用后续中间件:

import { authMiddleware } from "@clerk/nextjs";
import type { NextMiddleware } from 'next/server';
import type { NextRequest } from 'next/server';

export const Authentication = (next: NextMiddleware) => {
  const clerkMiddleware = authMiddleware({
    publicRoutes: [
      "/(.*)",
      "/signin(.*)",
      "/signup(.*)",
      "/sso-callback(.*)",
    ],
  });

  return async (req: NextRequest) => {
    // 先执行Clerk认证逻辑
    const authResponse = await clerkMiddleware(req);
    
    // 如果Clerk返回了响应(比如重定向到登录页),直接返回该响应
    if (authResponse) return authResponse;
    
    // 认证通过,调用下一个中间件
    return next(req);
  };
};

2. 修正internationalization.ts

同样将国际化中间件改为高阶函数结构,支持链式调用:

import { NextResponse, NextRequest } from "next/server";
import acceptLanguage from "accept-language";
import { fallbackLng, languages, cookieName } from "@/app/i18n/settings";
import type { NextMiddleware } from 'next/server';

acceptLanguage.languages(languages);

export const Internationalization = (next: NextMiddleware) => {
  return (req: NextRequest) => {
    // 静态资源直接跳过,调用下一个中间件
    if (
      req.nextUrl.pathname.indexOf("icon") > -1 ||
      req.nextUrl.pathname.indexOf("chrome") > -1
    )
      return next(req);

    let lng: string;
    if (req.cookies.has(cookieName))
      lng = acceptLanguage.get(req.cookies.get(cookieName).value);
    if (!lng) lng = acceptLanguage.get(req.headers.get("Accept-Language"));
    if (!lng) lng = fallbackLng;

    // 路径不包含支持的语言时,重定向到对应语言路径
    if (
      !languages.some((loc) => req.nextUrl.pathname.startsWith(`/${loc}`)) &&
      !req.nextUrl.pathname.startsWith("/_next")
    ) {
      return NextResponse.redirect(
        new URL(`/${lng}${req.nextUrl.pathname}`, req.url),
      );
    }

    let response: NextResponse | undefined;
    // 从referer中获取语言并设置cookie
    if (req.headers.has("referer")) {
      const refererUrl = new URL(req.headers.get("referer"));
      const lngInReferer = languages.find((l) =>
        refererUrl.pathname.startsWith(`/${l}`),
      );
      response = NextResponse.next();
      if (lngInReferer) response.cookies.set(cookieName, lngInReferer);
    }

    // 有自定义响应则返回,否则调用下一个中间件
    return response ?? next(req);
  };
};

3. 保持chain.ts和middleware.ts不变

你的链式调用核心逻辑和入口文件无需修改,现在类型会自动匹配:

// middleware.ts
import { chain } from '@/middlewares/chain'
import { Internationalization } from '@/middlewares/internationalization';
import { Authentication } from '@/middlewares/authentication';

export default chain([Authentication, Internationalization])

export const config = {
  matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};
// chain.ts
import { NextResponse } from 'next/server'
import type { NextMiddleware } from 'next/server'

type MiddlewareFactory = (middleware: NextMiddleware) => NextMiddleware

export function chain(
  functions: MiddlewareFactory[],
  index = 0
): NextMiddleware {
  const current = functions[index]

  if (current) {
    const next = chain(functions, index + 1)
    return current(next)
  }

  return () => NextResponse.next()
}

关键说明

  • 链式中间件的执行顺序由chain数组的顺序决定:先执行Authentication,再执行Internationalization,如果需要调整顺序,只需调换数组中两个中间件的位置。
  • 每个中间件可以通过返回NextResponse终止链式调用(比如认证失败的重定向),或者调用next(req)将请求传递给下一个中间件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 23:26:06