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

如何在Next.js中间件中调用tRPC过程实现用户重定向?

解决方案

方案一:使用tRPC Server Caller(推荐)

直接在中间件中创建tRPC服务端调用器,绕过客户端hooks直接执行tRPC过程。所有逻辑都在服务端运行,不会暴露Prisma或敏感数据到前端,安全且高效。

修改后的代码

import { getAuth, withClerkMiddleware } from "@clerk/nextjs/server";
import { type NextRequest, NextResponse } from "next/server";
import { appRouter } from "./server/api/root";
import { createTRPCContext } from "./server/api/trpc"; // 导入你项目中已有的tRPC上下文创建函数

export default withClerkMiddleware(async (req: NextRequest, opts) => {
  const { userId } = getAuth(req);

  if (userId) {
    // 构建与API路由一致的tRPC上下文
    const ctx = await createTRPCContext({ req, resHeaders: new Headers() });
    // 创建tRPC服务端调用器
    const caller = appRouter.createCaller(ctx);

    try {
      // 调用tRPC过程查询用户数据
      const user = await caller.ptusers.getOne({ id: userId });
      
      // 用户不存在则重定向至注册页
      if (!user) {
        return NextResponse.redirect(new URL("/sign-up", req.url));
      }
    } catch (error) {
      // 处理查询错误(比如你的tRPC过程在用户不存在时抛出错误)
      return NextResponse.redirect(new URL("/sign-up", req.url));
    }
  }

  return NextResponse.next();
});

export const config = {
  matcher: "/((?!_next/image|_next/static|favicon.ico|bg-signup.jpg|sign-up).*)", // 排除注册页避免循环重定向
};

关键说明

  • 复用项目中已有的tRPC上下文创建函数,确保权限校验、数据访问逻辑和API路由完全一致。
  • 通过appRouter.createCaller(ctx)创建服务端调用器,直接执行tRPC过程,无需依赖客户端hooks。

方案二:通过Edge API Route间接查询

如果不想在中间件中直接依赖tRPC路由,可以创建一个Edge API Route封装数据库查询逻辑,中间件通过HTTP请求调用该API。

步骤1:创建Edge API Route(app/api/check-user/route.ts)

import { getAuth } from "@clerk/nextjs/server";
import { NextResponse } from "next/server";
import { prisma } from "@/server/db";

export async function GET(req: Request) {
  const { userId } = getAuth(req);
  if (!userId) return NextResponse.json({ exists: false }, { status: 401 });

  const user = await prisma.ptusers.findUnique({ where: { id: userId } });
  return NextResponse.json({ exists: !!user });
}

步骤2:在中间件中调用该API

import { getAuth, withClerkMiddleware } from "@clerk/nextjs/server";
import { type NextRequest, NextResponse } from "next/server";

export default withClerkMiddleware(async (req: NextRequest, opts) => {
  const { userId } = getAuth(req);

  if (userId) {
    try {
      // 调用Edge API查询用户是否存在
      const res = await fetch(new URL("/api/check-user", req.url), {
        headers: {
          ...req.headers, // 传递Clerk认证头,确保API能获取用户ID
          "Content-Type": "application/json",
        },
      });

      const { exists } = await res.json();
      if (!exists) {
        return NextResponse.redirect(new URL("/sign-up", req.url));
      }
    } catch (error) {
      return NextResponse.redirect(new URL("/sign-up", req.url));
    }
  }

  return NextResponse.next();
});

export const config = {
  matcher: "/((?!_next/image|_next/static|favicon.ico|bg-signup.jpg|sign-up).*)",
};

关键说明

  • 通过API Route隔离数据库操作,中间件仅做HTTP请求,降低耦合度。
  • 需传递认证头,确保API Route能正确识别当前用户。
  • 性能略低于方案一,因为多了一次内部HTTP请求。

额外注意事项

  • Next.js中间件运行在Edge Runtime,确保你的依赖(如Prisma)支持Edge环境(Prisma 4.16+提供Edge Client)。
  • 务必在中间件匹配规则中排除注册页,避免出现循环重定向问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 12:29:54