【问题标题】:NextJS consistently access request object for every pageNextJS 一致地访问每个页面的请求对象
【发布时间】:2020-09-27 06:37:44
【问题描述】:

我正在使用express + passport + nextjs 来设置将使用 OpenID Connect 执行身份验证的应用。用户数据使用express-session 存储在请求对象上,这会像往常一样在每个请求上为我提供req.user

现在我想将用户信息传递给前端,以便我可以将其用于某些事情,但似乎没有任何一致的方法可以为所有请求执行此操作。我可以将getServerSideProps 用于单个页面,但不能通过_document_app 用于每个页面。我该如何设置?

这是我目前的_document.tsx

import Document, {
  Head,
  Main,
  NextScript,
  DocumentContext,
} from "next/document"

export default class Doc extends Document {
  public static async getInitialProps(ctx: DocumentContext) {
    const req: any = ctx.req
    console.log("req/user", `${!!req}/${!!(req && req.user)}`)
    const initialProps = await Document.getInitialProps(ctx)
    return {
      ...initialProps,
      user: req?.user || "no user",
    }
  }

  public render() {
    return (
      <html>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </html>
    )
  }
}

它似乎只在第一个请求期间返回请求对象,而不是任何后续页面刷新。

我创建了一个小型 repo,在此处重现该问题:https://github.com/rudfoss/next-server-custom-req

没有办法以简单的方式对所有页面执行此操作似乎很荒谬。

编辑:作为参考,这是我的server.js。它是 repo 中唯一的其他相关文件

const express = require("express")
const next = require("next")

const dev = process.env.NODE_ENV !== "production"

const start = async () => {
  console.log("booting...")
  const server = express()
  const app = next({ dev, dir: __dirname })
  const handle = app.getRequestHandler()
  await app.prepare()

  server.use((req, res, next) => {
    req.user = {
      authenticated: false,
      name: "John Doe",
    }
    next()
  })

  server.get("*", handle)

  server.listen(3000, (err) => {
    if (err) {
      console.error(err)
      process.exit(1)
    }

    console.log("ready")
  })
}

start().catch((error) => {
  console.error(error)
  process.exit(1)
})

【问题讨论】:

    标签: express next.js


    【解决方案1】:

    建议通过函数组件来实现,见Next.js custom App docs

    // /pages/_app.tsx
    import App, { AppProps, AppContext } from 'next/app'
    
    export default function MyApp({ Component, pageProps }: AppProps) {
      return <Component {...pageProps} />
    }
    
    MyApp.getInitialProps = async (appContext: AppContext) => {
      // calls page's `getInitialProps` and fills `appProps.pageProps`
      const appProps = await App.getInitialProps(appContext)
      const req = appContext.ctx.req
    
      return {
        pageProps: {
          ...appProps.pageProps,
          user: req?.user,
        },
      }
    }
    

    正如您的回答,这将在每个请求上运行,但自动静态优化不会处于活动状态。

    尝试在以下 CodeSandbox 上将 pageProps 更改为 MyApp.getInitialProps(不使用 req.user)的演示:

    https://codesandbox.io/s/competent-thompson-l9r1u?file=/pages/_app.js

    【讨论】:

      【解决方案2】:

      原来我可以在 _app 上覆盖 getInitialProps 来完成这项工作:

      class MyApp extends App {
        public static async getInitialProps({
          ctx
        }: AppContext): Promise<AppInitialProps> {
          const req: any = ctx.req
          return {
            pageProps: {
              user: req?.user
            }
          }
        }
      
        public render() {
          //...
        }
      }
      

      这将在每个请求上运行,但静态优化不起作用,但在我的情况下,我需要这些信息,所以我愿意接受权衡。

      编辑:此答案也有效,但它使用不再推荐的“旧”基于类的组件语法。有关使用功能组件语法的更现代版本,请参阅 Karl 的回答。

      【讨论】:

      • 很好,所以当getServerSidePropsgetStaticProps 在页面中定义时也运行此函数?编辑:...哦,我猜不是。
      • 能否也提供功能组件版本?
      • @Karl 到目前为止,我不再有可以测试它的环境,但函数方法应该是简单地从_app 文件中获取export const getInitialProps。不过我还没有测试过。
      • 啊,据我所知,它更像是这种格式:const App = () =&gt; {}; App.getInitialProps = async () =&gt; {}; 看这里:nextjs.org/docs/advanced-features/custom-app
      • 好的,发布答案:stackoverflow.com/a/62406237/1268612
      【解决方案3】:

      我也遇到了类似的问题,我必须从我的 Auth api 获取已登录的用户详细信息。我通过将整个应用程序包装在上下文提供程序中来解决它,然后对 initialState 使用 set 函数,该函数将记住它之前是否被调用并仅获取一次用户详细信息。然后在我的每个页面中,无论我需要这些用户详细信息,我都使用上下文查看详细信息是否可用,如果详细信息不可用,则调用 set 函数。这种方式我认为我实现了:

      1. 只有一个请求来获取用户详细信息
      2. 因为它发生在客户端,TTFB 更好
      3. 我仍然可以在需要的地方利用 getStaticProps 和 getServerSideProps。

      【讨论】:

        猜你喜欢
        • 2013-03-25
        • 2023-01-24
        • 2012-10-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多