Next.js App Router中如何将Middleware的数据传递到page.tsx?
Next.js App Router中如何将Middleware的数据传递到page.tsx?
兄弟,我太懂你折腾好几个小时的痛苦了😅!在Next.js App Router里,Middleware和Server Component的数据流逻辑确实和旧的Pages Router不太一样,我结合你的代码给你几个靠谱的解决方案:
方案一:最推荐!直接在Server Component里获取用户数据(利用Middleware的前置校验)
你的Middleware已经帮你把无效请求(没有session-token或者token失效)都重定向到首页了,所以能进入/cfa页面的请求,session-token肯定是有效的。那咱完全不用费劲在Middleware和页面之间传数据,直接在page.tsx(默认是Server Component)里读取cookie、调用getUser就行,代码逻辑还更顺:
修改你的page.tsx:
import { FormCreateLocation } from "@/components/forms/FormCreateLocation"; import { Location } from "@/components/resources/Location"; import { getUser } from "@/lib/getUser"; import { cookies } from "next/headers"; // 注意这里导入的是next/headers,不是client目录下的 export default async function Home() { // 直接在页面里读取session-token const sessionToken = cookies().get('session-token')?.value; // 因为Middleware已经做了校验,这里sessionToken肯定有值,不用再处理重定向 const userRequest = await getUser(sessionToken!); const userJson = await userRequest.json(); return ( <main className=""> {/* 把用户数据传给需要的组件 */} <FormCreateLocation user={userJson} /> <div className="p-4"> {/* 直接使用用户数据 */} <h2>欢迎回来,{userJson.email}!</h2> <h2>Select a Location</h2> <ul> <Location _id="0333333333" name="Chick-fil-A Highway 22" number="03444" /> <Location _id="33222222222" name="Chick-fil-A Midtown" number="03253" /> </ul> </div> </main> ); }
这个方案完全符合Next.js App Router的设计理念——Server Component本来就是用来在服务器端获取数据的,而且Middleware的前置校验已经帮我们过滤了无效请求,页面里不用再处理错误分支,代码简洁又可靠。
方案二:将用户数据存入加密Cookie(适合不想重复调用API的场景)
如果你确实想在Middleware里把用户数据传递到页面,可以把用户数据加密后存入Cookie,然后在页面里读取解密。注意一定要加密,不然敏感信息会暴露在浏览器里!
第一步:修改Middleware
import { NextRequest, NextResponse } from "next/server" import { getUser } from "./lib/getUser"; // 你需要自己实现加密/解密函数,比如用Node.js的crypto模块 import { encrypt } from "./lib/encrypt"; export async function middleware(request: NextRequest) { const sessionToken = request.cookies.get('session-token') if (!sessionToken) { return NextResponse.redirect(new URL('/', request.url)) } const userRequest = await getUser(sessionToken.value) if (userRequest.status !== 200) { return NextResponse.redirect(new URL('/', request.url)) } const userJson = await userRequest.json() // 加密用户数据 const encryptedUser = encrypt(JSON.stringify(userJson)) // 创建响应并设置加密后的Cookie const response = NextResponse.next() response.cookies.set('user-data', encryptedUser, { httpOnly: true, // 禁止前端JS读取,提升安全性 secure: process.env.NODE_ENV === 'production', // 生产环境下仅HTTPS传输 sameSite: 'strict', path: '/cfa' // 仅在/cfa路径下生效 }) return response } export const config = { matcher: "/cfa", }
第二步:修改page.tsx读取Cookie
import { FormCreateLocation } from "@/components/forms/FormCreateLocation"; import { Location } from "@/components/resources/Location"; import { decrypt } from "@/lib/decrypt"; // 对应加密的解密函数 import { cookies } from "next/headers"; import { redirect } from "next/navigation"; export default async function Home() { const encryptedUser = cookies().get('user-data')?.value; // 兜底处理(理论上Middleware已经拦截了无效请求) if (!encryptedUser) { redirect('/'); } // 解密并解析用户数据 const userJson = JSON.parse(decrypt(encryptedUser)); return ( <main className=""> <FormCreateLocation user={userJson} /> <div className="p-4"> <h2>欢迎回来,{userJson.email}!</h2> <h2>Select a Location</h2> <ul> <Location _id="0333333333" name="Chick-fil-A Highway 22" number="03444" /> <Location _id="33222222222" name="Chick-fil-A Midtown" number="03253" /> </ul> </div> </main> ); }
为什么你之前的方法没生效?
你尝试的设置自定义Header、修改NextRequest对象这些方式,在App Router里不太可靠:
- 自定义Header:Next.js在处理请求时,Middleware设置的自定义Header可能不会被传递到Server Component的请求上下文里(因为内部会重构请求);
- 修改NextRequest:Middleware里的Request实例是临时的,页面拿到的是新的Request对象,所以修改后的数据传不过去。
总的来说,方案一是最省心的,推荐优先使用!
备注:内容来源于stack exchange,提问作者Phillip England
相关产品推荐
相关产品推荐

