使用 getServerSideProps 获取内部 API? (Next.js)

Posted

技术标签:

【中文标题】使用 getServerSideProps 获取内部 API? (Next.js)【英文标题】:Internal API fetch with getServerSideProps? (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.

【问题讨论】:

【参考方案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,您甚至可以将useSWRs-s-r 一起使用。

【讨论】:

我只是使用环境变量来完成绝对路径。

以上是关于使用 getServerSideProps 获取内部 API? (Next.js)的主要内容,如果未能解决你的问题,请参考以下文章

getServerSideProps 与直接在 React 中获取

Nextjs Auth0 在 getServerSideProps 中获取数据

在 NextJs 中如何使用更改事件更改 getServerSideProps

如何在 getServerSideProps 之外获取 cookie?

在 NEXTJS 的 getServerSideProps() 中获取一些 html 表单数据(或对象)

NextJS + Apollo:如何在 getServerSideProps 内的 apolloClient.query 上获取多个查询?