如何将_app的getServerSideProps数据传递给页面的getServerSideProps?
能否将_app的getServerSideProps数据传递给页面的getServerSideProps?
场景描述
我有一个自定义的_app组件,其中包含getServerSideProps方法,在此处验证用户是否已认证,若已认证则从数据库加载用户数据,随后将isAuthenticated和user这两个值传递给_app的props。
同时我还有多个实际页面,部分公开、部分需要权限校验,这些页面也有自己的getServerSideProps方法。我希望在页面的getServerSideProps中直接复用_app里已加载的用户数据,避免两次加载用户信息——一次在_app层面,一次在页面层面。
现有代码示例
// pages/_app.jsx const App = ... App.getServerSideProps = async(context) => { let isAuthenticated = false; let user = {}; if (context?.req) { // get token from Cookies, validate token & load user } return { props: { isAuthenticated, user }, } }
// pages/profile.jsx const ProfilePage = ... ProfilePage.getServerSideProps = async(context) => { // get token, load user - in this step, I'd like to reuse the previously loaded data if (!isAuthenticated || !user.HAS_SOME_SPECIFIC_PERMISSION) { return { redirect: { destination: '/login', }, } } return { props: {} } }
解决方案
Next.js中,_app的getServerSideProps和页面的getServerSideProps是独立执行的,但两者共享同一次请求的req对象。我们可以利用这一点,通过提取公共认证逻辑+请求级缓存的方式实现数据复用:
1. 提取公共认证函数
创建一个独立的工具函数,封装用户认证、数据加载逻辑,并将结果缓存到req对象上:
// utils/auth.js export async function getUserFromRequest(req) { // 优先读取请求缓存的用户数据 if (req.userData) { return req.userData; } let isAuthenticated = false; let user = {}; if (req) { // 从Cookie获取token、验证并加载用户数据的逻辑 // 示例: // const token = req.cookies.token; // if (token) { // user = await db.user.findUnique({ where: { token } }); // isAuthenticated = !!user; // } } // 将数据缓存到req对象,供同一次请求的后续调用复用 req.userData = { isAuthenticated, user }; return req.userData; }
2. 在_app中使用公共函数
修改_app的getServerSideProps,调用公共函数获取用户数据:
// pages/_app.jsx import { getUserFromRequest } from '../utils/auth'; const App = ({ Component, pageProps, isAuthenticated, user }) => { return <Component {...pageProps} isAuthenticated={isAuthenticated} user={user} />; }; App.getServerSideProps = async (context) => { const userData = await getUserFromRequest(context.req); return { props: { ...userData }, }; }; export default App;
3. 在页面中复用数据
页面的getServerSideProps同样调用公共函数,此时会直接读取req上缓存的数据,无需重复查询数据库:
// pages/profile.jsx import { getUserFromRequest } from '../utils/auth'; const ProfilePage = () => { return <div>Profile Page</div>; }; ProfilePage.getServerSideProps = async (context) => { const { isAuthenticated, user } = await getUserFromRequest(context.req); if (!isAuthenticated || !user.HAS_SOME_SPECIFIC_PERMISSION) { return { redirect: { destination: '/login', }, }; } return { props: {} }; }; export default ProfilePage;
补充说明
- 该方案仅适用于Next.js Pages Router,App Router的逻辑会有差异。
- 因为是基于请求级缓存,每次请求都会重新加载用户数据,不会出现跨请求的脏数据问题。
内容的提问来源于stack exchange,提问作者Patrik Šimunič
相关产品推荐
相关产品推荐

