【问题标题】:Internal API fetch with getServerSideProps? (Next.js)使用 getServerSideProps 获取内部 API? (Next.js)
【发布时间】:2021-04-21 11:26:01
【问题描述】:

我是 Next.js 的新手,我正在尝试了解建议的结构并处理页面或组件之间的数据。

例如,在我的页面home.js 中,我获取了一个名为/api/user.js 的内部API,它从MongoDB 返回一些用户数据。我这样做是通过使用fetch()getServerSideProps() 中调用API 路由来实现的,该路由经过一些计算后将各种道具传递给页面。

据我了解,这有利于 SEO,因为道具会在服务器端获取/修改,并且页面可以让它们准备好呈现。但后来我在 Next.js 文档中读到,您不应该将 fetch() 用于 getServerSideProps() 中的所有 API 路由。那么我应该怎么做才能遵守良好的做法和良好的 SEO?

我没有在 API 路由本身中对 home.js 进行所需计算的原因是我需要来自此 API 路由的更多通用数据,因为我也会在其他页面中使用它。

我还必须考虑缓存,哪个客户端使用 SWR 来获取内部 API 非常简单,但服务器端我还不确定如何实现它。

home.js:

export default function Page({ prop1, prop2, prop3 }) {
        // render etc.
}

export async function getServerSideProps(context) {
  const session = await getSession(context)
  let data = null
  var aArray = [], bArray = [], cArray = []
  const { db } = await connectToDatabase()

  function shuffle(array) {
    var currentIndex = array.length, temporaryValue, randomIndex;
    while (0 !== currentIndex) {
      randomIndex = Math.floor(Math.random() * currentIndex);
      currentIndex -= 1;
      temporaryValue = array[currentIndex];
      array[currentIndex] = array[randomIndex];
      array[randomIndex] = temporaryValue;
    }
    return array;
  }

  if (session) {
    const hostname = process.env.NEXT_PUBLIC_SITE_URL
    const options = { headers: { cookie: context.req.headers.cookie } }
    const res = await fetch(`${hostname}/api/user`, options)
    const json = await res.json()
    if (json.data) { data = json.data }

    // do some math with data ...
    // connect to MongoDB and do some comparisons, etc.

【问题讨论】:

    标签: javascript node.js next.js server-side-rendering fetch-api


    【解决方案1】:

    但后来我在 Next.js 文档中读到,您不应该将 fetch() 用于 getServerSideProps() 中的所有 API 路由。

    您希望直接在 getServerSideProps 中使用 API 路由中的逻辑,而不是调用您的内部 API。那是因为getServerSideProps 就像 API 路由一样在服务器上运行(从服务器向服务器本身发出请求是没有意义的)。您可以从文件系统读取或直接从getServerSideProps 访问数据库。

    (注意the same applies when using getStaticProps/getStaticPaths methods


    这是一个小的重构示例,它允许您在 getServerSideProps 中重用来自 API 路由的逻辑。

    假设您有这个简单的 API 路由。

    // pages/api/user
    export default async function handler(req, res) {
        // Using a fetch here but could be any async operation to an external source
        const response = await fetch(/* external API endpoint */)
        const jsonData = await response.json()
        res.status(200).json(jsonData)
    }
    

    您可以将获取逻辑提取到一个单独的函数中(如果需要,仍然可以将其保存在api/user),它仍然可以在 API 路由中使用。

    // pages/api/user
    export async function getData() {
        const response = await fetch(/* external API endpoint */)
        const jsonData = await response.json()
        return jsonData
    }
    
    export default async function handler(req, res) {
        const jsonData = await getData()
        res.status(200).json(jsonData)
    }
    

    而且还允许您在getServerSideProps 中重复使用getData 函数。

    // pages/home
    import { getData } from './api/user'
    
    //...
    
    export async function getServerSideProps(context) {
        const jsonData = await getData()
        //...
    }
    

    【讨论】:

    • 导出功能是我在其他地方也需要的,我需要一个可重用的功能,但没有人建议我以这种方式导出它,谢谢,我会试试这个
    • 绝对,在某些情况下我解决它的另一种方法是使用“useSWR”客户端,它也会自动缓存请求。
    • 太棒了!沮丧了一整天发现这终于可以立即在框中获取数据了!为什么 api/routes 不直接为什么需要以其他方式提供它,他们采取了什么样的方法来建立,我不明白!一切都是为了在我们的头上绕圈子!抱歉,这可能是我令人沮丧的评论!
    • 这很奇怪,从其他优秀的文档中看不清楚
    【解决方案2】:

    尝试使用useSWR,示例如下

    import useSWR from 'swr'
    import React from 'react';
    
    //important to return only result, not Promise
    const fetcher = (url) => fetch(url).then((res) => res.json());
    
    const Categories = () => {
     //getting data and error
     const { data, error } = useSWR('/api/category/getCategories', fetcher)
     if (error) return <div>Failed to load</div>
     if (!data) return <div>Loading...</div>
     if (data){
       // {data} is completed, it's ok!
       //your code here to make something with {data}
       return (
          <div>
          //something here, example {data.name}
          </div>
       )
     }
    }
    
    export default Categories
    

    请注意,fetch 仅限 supports absolute URLs,这就是我不喜欢使用它的原因。

    附:根据docs,您甚至可以将useSWRSSR 一起使用。

    【讨论】:

    • 我只是使用环境变量来完成绝对路径。
    猜你喜欢
    • 2021-12-08
    • 2020-12-13
    • 1970-01-01
    • 2020-12-30
    • 2021-11-14
    • 2020-10-14
    • 2021-11-11
    • 1970-01-01
    相关资源
    最近更新 更多