Next 1.0


# 简介

Next.js 是一个 React 开发框架。它能确保您和您的团队成功地构建 React 应用程序。

Next.js 具有同类框架中最佳的 “开发人员体验” 和许多内置功能。列举其中一些如下:

  • 直观的、 基于页面 的路由系统(并支持 动态路由 )

  • 预渲染 。支持在页面级的 静态生成(SSG) 和 服务器端渲染(SSR)

  • 自动代码拆分,提升页面加载速度

  • 具有经过优化的预取功能的 客户端路由

  • 内置 CSS 和 Sass 的支持,并支持任何 CSS-in-JS 库

  • 开发环境支持 快速刷新

  • 利用 Serverless Functions 及 API 路由 构建 API 功能

  • 完全可扩展

    Next.js 被用于数以万计的的网站和 Web 应用程序,包括许多世界上许多最大的品牌都在使用 Next.js。

# 入门 —— 基本特性

# 页面 (Pages)

在 Next.js 中,一个 page(页面) 就是一个从 .js 、 .jsx 、 .ts 或 .tsx 文件导出(export)的 React 组件 ,这些文件存放在 pages 目录下。 每个 page(页面)都使用其文件名作为路由(route)

示例: 如果你创建了一个命名为 pages/about.js 的文件并导出(export)一个如下所示的 React 组件,则可以通过 /about 路径进行访问。

# 动态路由页面

Next.js 支持具有动态路由的 pages(页面)。例如,如果你创建了一个命名为 pages/posts/[id].js 的文件,那么就可以通过 posts/1 、 posts/2 等类似的路径进行访问。

# 获取数据

默认情况下,Next.js 将 预渲染 每个 page(页面)。这意味着 Next.js 会 预先为每个页面生成 HTML 文件,而不是由客户端 JavaScript 来完成 。预渲染可以带来更好的性能和 SEO 效果。

每个生成的 HTML 文件都与该页面所需的最少 JavaScript 代码相关联 。当浏览器加载一个 page(页面)时,其 JavaScript 代码将运行并使页面完全具有交互性。(此过程称为 水合(hydration) 。)

Next.js 具有两种形式的预渲染: 静态生成(Static Generation) 和 服务器端渲染(Server-side Rendering) 。这两种方式的不同之处在于 为 page(页面)生成 HTML 页面的 时机 :

  • 静态生成 (推荐) :HTML 在 构建时 生成,并在每次页面请求(request)时重用
  • 服务器端渲染 :在 每次页面请求(request)时 重新生成 HTML

重要的是,Next.js 允许你为每个页面 选择 预渲染的方式。 你可以创建一个 “混合渲染” 的 Next.js 应用程序 :对大多数页面使用 “静态生成”,同时对其它页面使用 “服务器端渲染”。

出于性能考虑,相对服务器端渲染,我们更 推荐 使用 静态生成 。CDN 可以在没有额外配置的情况下缓存静态生成的页面以提高性能。但是,在某些情况下,服务器端渲染可能是唯一的选择。

你还可以将 客户端渲染 与静态生成或服务器端渲染一起使用。这意味着页面的某些部分可以完全由客户端 JavaScript 呈现。

# 静态生成

如果一个页面使用了 静态生成 ,在 构建时(build time) 将生成此页面对应的 HTML 文件。 这意味着在生产环境中,运行 next build 时将生成该页面对应的 HTML 文件 。 然后,此 HTML 文件将在每个页面请求时被重用,还可以被 CDN 缓存 。

  • 需要获取数据的静态生成

    某些页面需要 获取外部数据 以进行预渲染。有两种情况,一种或两种都可能适用。在每种情况下,你都可以使用 Next.js 所提供的以下函数:

    • 您的页面 内容 取决于外部数据:使用 getStaticProps 。

      例如:您的博客页面可能需要从 CMS(内容管理系统)中获取博客文章列表。要在预渲染时获取此数据,Next.js 允许你从同一文件 export(导出) 一个名为 getStaticProps 的 async(异步) 函数。 该函数在构建时被调用 ,并允许你在 预渲染 时将获取的数据作为 props 参数传递给页面。

      什么时候使用 getStaticProps :1. 呈现页面所需的数据在用户请求之前的构建时可用。2. 数据可以公开缓存(非用户特定)。3. 该页面必须预渲染(用于 SEO)并且速度非常快 —— getStaticProps 生成 HTML 和 JSON 文件,这两种文件都可以由 CDN 缓存 以提高性能。

      // 需要获取 `posts`(通过调用 API )
      // 在此页面被预渲染之前
      function Blog({ posts }) {
        return (
          <ul>
            {posts.map((post) => (
              <li>{post.title}</li>
            ))}
          </ul>
        );
      }
      
      // 此函数在构建时被调用
      export async function getStaticProps(context) {
        // context参数是一个包含很多键的对象,其中最重要的是params:包含使用动态路由的页面的路由参数
        // 调用外部 API 获取博文列表
        const res = await fetch("https://.../posts");
        const posts = await res.json();
      
        // 通过返回 { props: { posts } } 对象,Blog 组件
        // 在构建时将接收到 `posts` 参数
        return {
          props: {
            posts,
          },
        };
      }
      
      export default Blog;
    • 你的页面 paths(路径) 取决于外部数据:使用 getStaticPaths (通常还要同时使用 getStaticProps )。
      Next.js 允许你创建具有 动态路由 的页面。例如,你可以创建一个名为 pages/posts/[id].js 的文件用以展示以 id 标识的单篇博客文章。当你访问 posts/1 路径时将展示 id: 1 的博客文章。但是,在构建 id 所对应的内容时可能需要从外部获取数据。例如:假设你只向数据库添加了一篇博客文章(标记为 id: 1 )。这种情况下,你只想在构建时针对 posts/1 进行预渲染。稍后,你又添加了第二篇文章,标记为 id: 2 。这是,你希望对 posts/2 也进行预渲染。因此,预渲染的页面 paths(路径) 取决于外部数据。为了解决这个问题,Next.js 允许你从动态页面(在这里是 pages/posts/[id].js )中 export(导出) 一个名为 getStaticPaths 的 async(异步) 函数。该函数在构建时被调用,并允许你指定要预渲染的路径。 指定动态路由,根据数据预渲染页面 。

      function Post({ post }) {
        // Render post...
      }
      
      export async function getStaticPaths() {
        // ...
      }
      
      // 在构建时也会被调用
      export async function getStaticProps({ params }) {
        // params 包含此片博文的 `id` 信息。
        // 如果路由是 /posts/1,那么 params.id 就是 1
        const res = await fetch(`https://.../posts/${params.id}`);
        const post = await res.json();
      
        // 通过 props 参数向页面传递博文的数据
        return { props: { post } };
      }
      
      export default Post;
    • 什么时候应该使用静态生成?
      我们建议您尽可能使用 静态生成 (带有或不带数据),因为你的所有 page(页面)都可以只构建一次并托管到 CDN 上,这比让服务器根据每个页面请求来渲染页面快得多。 您应该问问自己:“我可以在用户请求之前预先渲染此页面吗?” 如果答案是肯定的,则应选择“静态生成”。 另一方面,如果你无法在用户请求之前预渲染页面,则 “静态生成” 不是 一个好主意。 这也许是因为你的页面需要显示频繁更新的数据,并且页面内容会随着每个请求而变化。 在这种情况下,您可以执行以下任一操作:

      • 将 “静态生成” 与 客户端渲染 一起使用:你可以跳过页面某些部分的预渲染,然后使用客户端 JavaScript 来填充它们。
      • 使用 服务器端渲染: Next.js 针对每个页面的请求进行预渲染 。 由于 CDN 无法缓存该页面,因此速度会较慢,但是预渲染的页面将始终是最新的 。我们将在下面讨论这种方法。

# 服务器端渲染 (SSR / 动态渲染)

如果 page(页面)使用的是 服务器端渲染 ,则会在 每次页面请求时 重新生成页面的 HTML
要对 page(页面)使用服务器端渲染,你需要 export 一个名为 getServerSideProps 的 async 函数。服务器将在每次页面请求时调用此函数。

例如,假设你的某个页面需要预渲染频繁更新的数据(从外部 API 获取)。你就可以编写 getServerSideProps 获取该数据并将其传递给 Page ,如下所示:

function Page({ data }) {
  // Render data...
}

// This gets called on every request
export async function getServerSideProps() {
  // Fetch data from external API
  const res = await fetch(`https://.../data`);
  const data = await res.json();

  // Pass data to the page via props
  return { props: { data } };
}

export default Page;

如你所见, getServerSideProps 类似于 getStaticProps ,但两者的区别在于 getServerSideProps 在每次页面请求时都会运行,而在构建时不运行。

# 总结

  • 静态生成(推荐) : HTML 是在 构建时(build time) 生成的,并重用于每个页面请求。要使页面使用 “静态生成”,只需导出(export)页面组件或导出(export) getStaticProps 函数(如果需要还可以导出 getStaticPaths 函数)。对于可以在用户请求之前预先渲染的页面来说,这非常有用。你也可以将其与客户端渲染一起使用以便引入其他数据。
  • 服务器端渲染 : HTML 是在 每个页面请求 时生成的。要设置某个页面使用服务器端渲染,请导出(export) getServerSideProps 函数。由于 服务器端渲染会导致性能比“静态生成”慢 ,因此仅在绝对必要时才使用此功能。
  • 执行时机: getServerSideProps 在每个请求时执行,而 getStaticProps 在构建时执行。
  • 执行环境: getServerSideProps , getStaticProps 都只能在服务器端执行。
  • 数据更新: getServerSideProps 可以获取实时数据,因为它在每个请求时都会执行。而 getStaticProps 获取的数据在构建时就确定了,因此在构建后数据的更新需要重新构建。
  • 部署方式: getServerSideProps 的页面需要部署到服务器上,而 getStaticProps 的页面可以部署到静态文件托管服务上,例如 Vercel。
  • 性能: getServerSideProps 的页面每次请求都会执行获取数据的逻辑,可能会影响性能。而 getStaticProps 的页面在构建时就获取了数据,所以访问速度更快。
  • getServerSideProps 适用于需要实时数据的场景,而 getStaticProps 适用于数据不经常变化的场景。合理选择这两个函数可以提高页面性能和用户体验。

# 支持 Sass

Next.js 允许你导入(import)具有 .scss 和 .sass 扩展名的 Sass 文件。你可以通过 CSS 模块以及 .module.scss 或 .module.sass 扩展名来使用组件及的 Sass。

在使用 Next.js 的内置 Sass 支持前,请确保安装了 sass :

npm install sass

注意:Sass 支持 两种不同的语法 ,每种语法都有自己的扩展名。 .scss 扩展名要求你使用 SCSS 语法 , 而 .sass 扩展名要求你使用 缩进语法(即 "Sass")

/* variables.module.scss */
$primary-color: #64FF00

:export {
  primaryColor: $primary-color
}

// pages/_app.js
import variables from '../styles/variables.module.scss'

export default function MyApp({ Component, pageProps }) {
  return (
    <Layout color={variables.primaryColor}>
      <Component {...pageProps} />
    </Layout>
  )
}

# CSS-in-JS

可以使用任何现有的 CSS-in-JS 解决方案。最简单的一种是内联样式:

function HiThere() {
  return <p style={{ color: "red" }}>hi there</p>;
}

export default HiThere;

# Layout 布局

React 模型允许我们将页面解构为一系列组件。其中许多组件经常在页面之间重复使用。例如,您可能在每个页面上都有相同的导航栏和页脚。

// components/layout.js

import Navbar from "./navbar";
import Footer from "./footer";

export default function Layout({ children }) {
  return (
    <>
      <Navbar />
      <main>{children}</main>
      <Footer />
    </>
  );
}

# Image 组件及图片优化

Image 组件是 HTML 元素 <img/> 的扩展,Image 组件包含了各种内置性能优化,其中包括:

  • 改进的性能:始终使用现代图像格式为每个设备提供正确大小的图像。
  • 视觉稳定性:自动防止累积布局偏移。
  • 更快的页面加载:图像仅在进入视口时加载,带有可选的模糊占位符。
  • 资产灵活性:按需调整图像大小,即使是存储在远程服务器上的图像。

# 本地图片

  • src 属性可以是本地也可以是远程
  • Next.js 将根据导入的文件自动确定您的图像的 width 和 height 这些值用于防止加载图像时的累积布局偏移。
import Image from "next/image";】
import profilePic from '../public/me.png'
<Image
  src={profilePic}
  alt="Picture of the author"
  // width={500} automatically provided
  // height={500} automatically provided
  // blurDataURL="data:..." automatically provided
  // placeholder="blur" // Optional blur-up while loading
/>;

# 远程图片

要使用远程图像,该 src 属性应该是一个 URL 字符串。

  • 由于 Next.js 在构建过程中无法访问远程文件,因此您需要手动提供 width,height 和可选道具:blurDataURL(在图像成功加载之前用作占位符图像的数据 URL src。只有与 placeholder=“blur” 结合使用才有效。必须是 base64 编码的图像。它会被放大和模糊,因此建议使用非常小的图像(10px 或更小)。包含较大的图像作为占位符可能会损害您的应用程序性能。)
import Image from "next/image";

export default function Home() {
  return (
    <Image src="xxx" alt="Picture of the author" width={500} height={500} />
  );
}

# 域名

有时您可能想要访问远程图像,但仍使用内置的 Next.js 图像优化 API。为此,请保留 loader 其默认设置并为 Image 输入绝对 URL src。
为了保护您的应用程序免受恶意用户的攻击,您必须定义您打算以这种方式访问的远程域列表。这是在您的 next.config.js 文件中配置的,如下所示:

module.exports = {
  images: {
    domains: ["example.com", "example2.com"],
  },
};

# 优先事项

您应该将 priority(优先级属性) 添加到图像中,该图像将是每个页面的最大内容绘制(LCP)元素。这样做可以让 Next.js 专门为加载图像设置优先级(例如,通过预加载标签或优先级提示),从而大大提高 LCP 的性能。
LCP 元素通常是页面视口中可见的最大图像或文本块。当您运行 next dev 时,如果 LCP 元素是一个没有 priority(优先级属性) 的 <Image> ,您将看到一个控制台警告。
一旦你识别 LCP 图像后,可以添加如下属性:

import Image from "next/image";

export default function Home() {
  return (
    <>
      <h1>My Homepage</h1>
      <Image
        src="/me.png"
        alt="Picture of the author"
        width={500}
        height={500}
        priority
      />
      <p>Welcome to my homepage!</p>
    </>
  );
}

# 图像尺寸

图像最常见的损害性能的方式之一是通过布局转换,即图像加载时在页面上推动其他元素。这个性能问题对用户来说非常烦人,因此它有自己的核心 Web 重要功能,称为累积布局转换。避免基于图像的布局变化的方法是始终调整图像的大小。这允许浏览器在加载图像之前为其保留足够的空间。
可以使用以下三种方式之一调整大小:

  • 自动,使用静态引入。
  • 显示地,通过高度和宽度属性。
  • 隐含地,通过使用 layout='fill' ,使图像展开以填充其父元素。layout 还有 contain 及 cover 属性,使用 layout='fill' 时,父元素必须有 position: relative ,使用 layout='responsive' 时,父元素必须有 display: block

# 字体优化

要在 Next.js 应用程序中添加 web 字体,请覆盖 Next/head。例如,您可以将字体添加到特定页面:

import Head from "next/head";

export default function IndexPage() {
  return (
    <div>
      <Head>
        <link
          href="https://fonts.googleapis.com/css2?family=Inter&display=optional"
          rel="stylesheet"
        />
      </Head>
      <p>Hello world!</p>
    </div>
  );
}

# 禁用优化

如果您不希望 Next.js 优化您的字体,您可以选择关闭。

  • next.config.js

    module.exports = {
      optimizeFonts: false,
    };

# 脚本组件

Next.js 脚本组件 Next/Script 是 HTML <script> 元素的扩展。它使开发人员能够在应用程序中的任何位置设置第三方脚本的加载优先级,而无需直接附加到 next/head,从而在提高加载性能的同时节省了开发人员的时间。

import Script from "next/script";

export default function Home() {
  return (
    <>
      <Script src="https://www.google-analytics.com/analytics.js" />
    </>
  );
}

# 概述

网站通常使用第三方脚本在其网站中包含不同类型的功能,如分析、广告、客户支持小部件和同意管理。然而,这可能会带来影响用户和开发人员体验的问题:

  • 一些第三方脚本的加载性能很高,可能会降低用户体验,尤其是当它们呈现阻塞并延迟加载任何页面内容时
  • 开发人员经常很难决定在应用程序中放置第三方脚本的位置,以确保最佳加载

脚本组件使开发人员更容易将第三方脚本放置在应用程序的任何位置,同时优化其加载策略。

# 用法

import Script from "next/script";

# 策略

使用 next/script,您可以使用 strategy 策略属性决定何时加载第三方脚本:

<Script src="https://connect.facebook.net/en_US/sdk.js" strategy="lazyOnload" />

可以使用三种不同的加载策略:

  • beforeInteractive (交互之前):在页面交互之前加载

    • 使用 beforeInteractive 策略加载的脚本从服务器注入到初始 HTML 中,并在执行自绑定 JavaScript 之前运行。此策略应用于在页面交互之前需要获取和执行的任何关键脚本。
    <Script
      src="https://cdn.jsdelivr.net/npm/cookieconsent@3/build/cookieconsent.min.js"
      strategy="beforeInteractive"
    />
  • afterInteractive (互动后):(默认):在页面变成交互式后立即加载

    • 这种策略应该用于不需要尽快加载的脚本,并且可以在页面交互后立即获取和执行。
    <Script
      strategy="afterInteractive"
      dangerouslySetInnerHTML={{
        __html: `
      (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
      new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
      j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
      'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
      })(window,document,'script','dataLayer', 'GTM-XXXXXX');
    `,
      }}
    />
  • lazyOnload (懒加载):空闲时加载

    • 使用 lazyOnload 策略的脚本在获取所有资源后以及空闲时间加载较晚。此策略应用于后台或低优先级脚本,这些脚本不需要在页面交互之前或之后立即加载。
    <Script
      src="https://connect.facebook.net/en_US/sdk.js"
      strategy="lazyOnload"
    />

# 内联脚本

脚本组件也支持内联脚本或未从外部文件加载的脚本。它们可以通过将 JavaScript 放在大括号中来编写:

<Script id="show-banner" strategy="lazyOnload">
  {`document.getElementById('banner').classList.remove('hidden')`}
</Script>

或者使用 dangerouslySetInnerHTML 属性:

<Script
  id="show-banner"
  dangerouslySetInnerHTML={{
    __html: `document.getElementById('banner').classList.remove('hidden')`,
  }}
/>

将脚本组件用于内联脚本时需要注意两个限制:

  • 只能使用 afterInteractive 和 lazyOnload 策略。beforeInteractive 加载策略将外部脚本的内容注入到初始 HTML 响应中。内联脚本已经做到了这一点,这就是为什么 beforeInteractive 策略不能与内联脚本一起使用的原因。
  • 必须定义 id 属性,Next.js 才能跟踪和优化脚本

# 加载后执行代码 (onLoad)

一些第三方脚本要求用户在脚本加载完成后运行 JavaScript 代码,以便实例化内容或调用函数。如果加载脚本时使用 beforeInteractive 或 afterInteractive 作为加载策略,则可以在加载后使用 onLoad 属性执行代码:

import { useState } from "react";
import Script from "next/script";

export default function Home() {
  const [stripe, setStripe] = useState(null);

  return (
    <>
      <Script
        id="stripe-js"
        src="https://js.stripe.com/v3/"
        onLoad={() => {
          setStripe({ stripe: window.Stripe("pk_test_12345") });
        }}
      />
    </>
  );
}

# 附加属性

有许多 DOM 属性可以分配给 script 组件不使用的 <script> 元素,如 nonce 或 custom data attributes(自定义数据属性) 。包含任何附加属性将自动将其转发到最终的优化 <script> 元素,该元素将输出到页面。

import Script from "next/script";

export default function Home() {
  return (
    <>
      <Script
        src="https://www.google-analytics.com/analytics.js"
        id="analytics"
        nonce="XUENAJFW"
        data-test="analytics"
      />
    </>
  );
}

# 路由

# 页面路由

当一个文件被添加到 pages 目录中,它会自动作为路由使用。pages 目录中的文件可以用来定义最常见的模式。

# Index routes

路由器会自动将名为 index 的路由文件到目录的根目录。

  • pages/index.js → /
  • pages/blog/index.js → /blog

# 嵌套路由

路由器支持嵌套文件。如果创建嵌套文件夹结构,文件仍将以相同的方式自动路由。

  • pages/blog/first-post.js → /blog/first-post
  • pages/dashboard/settings/username.js → /dashboard/settings/username

# 动态路由

可以使用括号语法,这允许您匹配命名参数。

  • pages/blog/[slug].js → /blog/:slug (/blog/hello-world)
  • pages/[username]/settings.js → /:username/settings (/foo/settings)
  • pages/post/[...all].js → /post/* (/post/2020/id/title)

# 页面之间的链接

通过 Link 组件去进行跳转。

  • 案例

    import Link from "next/link";
    
    function Home() {
      return (
        <ul>
          <li>
            <Link href="/">
              <a>Home</a>
            </Link>
          </li>
          <li>
            <Link href="/about">
              <a>About Us</a>
            </Link>
          </li>
          <li>
            <Link href="/blog/hello-world">
              <a>Blog Post</a>
            </Link>
          </li>
        </ul>
      );
    }
    // / → pages/index.js
    // /about → pages/about.js
    // /blog/hello-world → pages/blog/[slug].js
    export default Home;

# 链接到动态路由

  • 案例

    import Link from "next/link";
    
    function Posts({ posts }) {
      return (
        <ul>
          {posts.map((post) => (
            <li key={post.id}>
              <Link href={`/blog/${encodeURIComponent(post.slug)}`}>
                <a>{post.title}</a>
              </Link>
            </li>
          ))}
        </ul>
      );
    }
    
    // 或者用 URL 对象
    function Posts({ posts }) {
      return (
        <ul>
          {posts.map((post) => (
            <li key={post.id}>
              <Link
                href={{
                  pathname: "/blog/[slug]",
                  query: { slug: post.slug },
                }}
              >
                <a>{post.title}</a>
              </Link>
            </li>
          ))}
        </ul>
      );
    }
    // pathname是页面目录中页面的名称,/blog/[slug]
    // query 是动态部分的对象,在这种情况下就是slug
    
    export default Posts;

# 注入路由器

要访问 React 组件中的路由器对象,可以使用 useRouter 或 withRouter 。这里通常会使用 useRouter
next/link 应该能够满足您的大部分路由需求,但您也可以在没有它的情况下进行客户端导航。

import { useRouter } from "next/router";

export default function ReadMore() {
  const router = useRouter();

  return (
    <button onClick={() => router.push("/about")}>
      Click here to read more
    </button>
  );
}

# 浅路由

浅路由允许您在不再次运行数据获取方法的情况下更改 URL,这些方法包括 getServerSideProps 、 getStaticProps 和 getInitialProps 。

您将通过路由器对象(通过 useRouter 或 withRouter 添加)接收更新的 pathname 和 query ,而不会丢失状态。

若要启用浅路由,请将 shallow 设置为 true 。

import { useEffect } from "react";
import { useRouter } from "next/router";

// 当前 URL 是 '/'
function Page() {
  const router = useRouter();

  useEffect(() => {
    // 始终在第一次渲染后进行导航
    router.push("/?counter=10", undefined, { shallow: true });
  }, []);

  useEffect(() => {
    // The counter changed!
  }, [router.query.counter]);
}

// URL将更新为/?counter=10。并且页面不会被替换,只会更改路由的状态。
export default Page;

注意:浅路由 只适用 于相同页面的 URL 更改。例如,假设我们有另一个名为 pages/about.js 的页面,您可以运行以下操作:

router.push("/?counter=10", "/about?counter=10", { shallow: true });

由于这是一个新页面,即使我们要求进行浅路由,它也会卸载当前页面,加载新页面并等待数据获取。

# API 路由

# 简介

API 路由为使用 Next.js 构建你自己的 API 提供了一种解决方案。

pages/api 目录下的任何文件都将作为 API 端点映射到 /api/\* ,而不是 page 。这些文件只会增加服务端文件包的体积,而不会增加客户端文件包的大小。

为了使 API 路由能正常工作,你需要导出(export)一个默认函数(即 请求处理器),并且该函数能够接收以下参数:

  • req : 一个 http.IncomingMessage 实例,以及一些预先构建的中间件
  • res : 一个 http.ServerResponse 实例,以及一些辅助函数

要处理 API 路由的不同 HTTP 方法,可以在请求处理器中使用 req.method ,如下所示:

export default function handler(req, res) {
  if (req.method === "POST") {
    // Process a POST request
  } else {
    // Handle any other HTTP method
  }
}

对于新项目,您可以使用 API Routes 构建整个 API。如果您有一个现有的 API,则不需要通过 API 路由将调用转发到 API。API 路由的其他一些用例包括:

  • 屏蔽外部服务的 URL(例如 /api/secret ,而不是 https://company.com/secret-url )
  • 使用服务器上的环境变量来安全地访问外部服务。

注意事项:

  • 如果 API 路由未指定 CORS 标头则意味着它们在默认情况下仅是同源策略。你可以通过使用 CORS 中间件包装出一个请求处理器来自定义此行为。

  • API 路由不能同 next export 一起使用

# 动态 API 路由

API 路由支持,并与 pages 一样遵循相同的文件命名规则。

例如,API 路由 pages/api/post/[pid].js 的实现代码如下:

export default function handler(req, res) {
  const { pid } = req.query;
  res.end(`Post: ${pid}`);
}

现在,发往 /api/post/abc 的请求将收到响应: Post: abc 。

# API 中间件

API 路由提供了内置的中间件,用于解析传入的请求 ( req )。这些中间件是:

  • req.cookies : 包含请求发送的 cookie 的对象。默认为{}
  • req.query : 包含查询字符串的对象。默认为{}
  • req.body : 包含按内容类型解析的正文的对象,如果未发送正文,则为 null

# 响应助手函数 (Response Helpers)

服务器响应对象 (通常缩写为 res)包括一组类似 Express.js 的辅助方法,以改善开发人员的体验并提高创建新 API 端点的速度。

  • 包括:

    • res.status(code) - 设置状态代码的功能。代码必须是有效的 HTTP 状态代码

      // 将响应发送回客户端时,您可以设置响应的状态代码。
      // 以下示例将响应的状态代码设置为200( OK) 并返回message值为 的属性Hello from Next.js!作为 JSON响应:
      export default function handler(req, res) {
        res.status(200).json({ message: "Hello from Next.js!" });
      }
    • res.json(body) - 发送 JSON 响应。body 必须是可序列化的对象

      // 将响应发送回客户端时,您可以发送 JSON 响应,这必须是可序列化的对象。在程序中,您可能希望根据请求端点的结果让客户端知道请求的状态。
      // 以下示例发送带有状态代码200( OK) 和异步操作结果的 JSON 响应。它包含在 try catch 块中,用于处理可能发生的任何错误,捕获适当的状态代码和错误消息并将其发送回客户端:
      export default async function handler(req, res) {
        try {
          const result = await someAsyncOperation();
          res.status(200).json({ result });
        } catch (err) {
          res.status(500).json({ error: "failed to load data" });
        }
      }
    • res.send(body) - 发送 HTTP 响应。主体可以是字符串、对象或缓冲区 (Buffer)

      // 发送 HTTP 响应的方式与发送 JSON 响应的方式相同。唯一的区别是响应正文可以是 a string、 anobject或 a Buffer。
      // 以下示例发送带有状态代码200( OK) 和异步操作结果的 HTTP 响应。
      export default async function handler(req, res) {
        try {
          const result = await someAsyncOperation();
          res.status(200).send({ result });
        } catch (err) {
          res.status(500).send({ error: "failed to fetch data" });
        }
      }
    • res.redirect([status,] path) - 重定向到指定的路径或 URL。status 必须是有效的 HTTP 状态代码。如果未指定,则状态默认为 “307”“临时重定向”。

      // 以表单为例,您可能希望在客户端提交表单后将其重定向到指定的路径或 URL。
      // /如果表单提交成功,以下示例将客户端重定向到该路径:
      export default async function handler(req, res) {
        const { name, message } = req.body;
        try {
          await handleFormInputAsync({ name, message });
          res.redirect(307, "/");
        } catch (err) {
          res.status(500).send({ error: "failed to fetch data" });
        }
      }

文章作者: Mrr-cxh
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Mrr-cxh !
赏
 上一篇
Next 性能优化 Next 性能优化
Next是一个React开发框架。它能确保您和您的团队成功地构建 React 应用程序。Next.js 具有同类框架中最佳的“开发人员体验”和许多内置功能。比如:服务端渲染(SSR)和页面级的静态生成(SSG);基于页面的路由系统(并支持动态路由);具有经过优化的预取功能的客户端路由…….Next.js被用于数以万计的网站和Web应用程序,包括许多世界上最大的品牌都在使用Next.js。
2023-10-15
下一篇 
React Native React Native
React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的JS框架 React 在原生移动应用平台的衍生产物,支持iOS和安卓两大平台。RN使用Javascript语言,类似于HTML的JSX,以及CSS来开发移动应用,因此熟悉Web前端开发的技术人员只需很少的学习就可以进入移动应用开发领域。
2022-11-28
  目录