NextJs 数据篇 - 数据获取 | 缓存 | Server Actions
NextJs 数据篇 - 数据获取 | 缓存 | Server Actions
- 前言
- 一. 数据获取 fetch
- 1.1 缓存 caching
- ① 服务端组件使用fetch
- ② 路由处理器 GET 请求使用fetch
- 1.2 重新验证 revalidating
- ① 基于时间的重新验证
- ② 按需重新验证
- revalidatePath
- revalidateTag
- 1.3 缓存的退出方式
- 二. Server Actions
- 2.1 PageRouter下 API 简单案例
- 2.2 AppRouter 下 Server Actions 简单案例
前言
之前讲了:
- NextJs 初级篇 - 安装 | 路由 | 中间件
- NextJs 渲染篇 - 什么是CSR、SSR、SSG、ISR 和服务端/客户端组件
这篇文章就打算专门讲一下NextJs中的数据获取方式、缓存以及什么是Server Actions
一. 数据获取 fetch
NextJs 中,在服务端使用 fetch 函数是常规的数据请求方式,它扩展了原生的API,在此基础上有这么几个功能(针对服务端的请求):
caching:缓存revalidating:重新验证
例如这么一个简单的服务端组件:
export default async function Page() {const res = await fetch('https://jsonplaceholder.typicode.com/posts')const data = await res.json()return (<ul>{data.map((item: any) => (<li key={item.id}>{item.title}</li>))}</ul>)
}
1.1 缓存 caching
默认情况下,NextJs 会自动缓存服务端中 fetch 请求的返回值。但是在以下情况下不会自动缓存:
- 在
Server Action中使用的时候。 - 在定义了非
GET方法的路由处理程序中使用。
即在服务端组件内部或者只有 GET 方法的路由处理程序中使用 fetch 函数,返回结果会自动缓存。
接下来我们来测试一下缓存,为了更加直观的让大家看到缓存的生效,我们可以在next.config.mjs 文件中增加以下配置,这样在fetch的时候,就会打印相关的信息,包括缓存是否命中
/** @type {import('next').NextConfig} */
const nextConfig = {logging: {fetches: {fullUrl: true}}
};export default nextConfig;
① 服务端组件使用fetch
例如我有这么一个服务端组件:
export default async function Page() {const res = await fetch('https://jsonplaceholder.typicode.com/posts')const data = await res.json()return (<ul>{data.map((item: any) => (<li key={item.id}>{item.title}</li>))}</ul>)
}
页面多次访问后:可以发现缓存命中

② 路由处理器 GET 请求使用fetch
// app/api/getData/route.ts
import { NextResponse } from 'next/server'export async function GET() {const res = await fetch('https://jsonplaceholder.typicode.com/posts')const data = await res.json()return NextResponse.json(data)
}
然后多次访问 http://localhost:3000/api/getData,结果如下:

1.2 重新验证 revalidating
重新验证的定义:清除缓存数据,然后重新获取最新的数据。 而NextJs 中提供了两种方式完成重新验证:
- 基于时间的重新验证:根据指定的时间,自动进行重新验证。
- 按需重新验证:根据事件手动重新验证数据。
① 基于时间的重新验证
这种验证方式,只需要在fetch的时候,增加参数revalidate即可,如下代表这个请求的缓存时长为10秒钟
fetch('https://...', { next: { revalidate: 10 } })
或者在路由段配置项中进行配置,可以再页面上或者路由处理程序中增加以下属性的导出:
// layout.jsx | page.jsx | route.js
export const revalidate = 10
② 按需重新验证
我们可以在路由处理程序中或者 Server Actions 中通过两种方式来实现按需重新验证:
- 路径
revalidatePath - 缓存标签
revalidateTag
revalidatePath
我们写一个简单的页面,这个页面每次加载的时候都会随机加载一个图片,但是由于fetch被缓存了,加载多次还是同一个图片。
async function getData() {// 接口每次调用都会返回一个随机的猫猫图片数据const res = await fetch('https://api.thecatapi.com/v1/images/search')if (!res.ok) {throw new Error('Failed to fetch data')}return res.json()
}export default async function Page() {const data = await getData()return <img src={data[0].url} width="300" />
}
效果如下:

那我如何按需让这个fetch请求做到刷新呢?例如我创建这么一个路由处理程序:
// app/api/revalidatePathTest/route.ts
import { revalidatePath } from 'next/cache'
import { NextRequest } from 'next/server'export async function GET(request: NextRequest) {const path = request.nextUrl.searchParams.get('path')if (path) {revalidatePath(path)return Response.json({ revalidated: true, now: Date.now() })}return Response.json({revalidated: false,now: Date.now(),message: 'Missing path to revalidate',})
}
这段代码啥意思呢?
- 如果我请求的地址没有参数
refreshPath,那就是个普通的接口。 - 如果我请求的地址带上参数
refreshPath,就会通过revalidatePath函数,重新验证对应路由或者接口。
倘若我访问:http://localhost:3000/api/revalidatePathTest?refreshPath=/,之后再访问:http://localhost:3000/,可见图片发生了刷新:

说明成功让路由 / 进行了重新验证(缓存刷新)
revalidateTag
除此之外,NextJs中有一个路由标签系统,即revalidateTag,它的实现逻辑如下:
使用 fetch 的时候,设置一个或者多个标签标记请求
调用 revalidateTag 方法重新验证该标签对应的所有请求
例如我们修改app/page.tsx文件:
async function getData() {// 接口每次调用都会返回一个随机的猫猫图片数据const res = await fetch('https://api.thecatapi.com/v1/images/search', { next: { tags: ['refresh'] } })if (!res.ok) {throw new Error('Failed to fetch data')}return res.json()
}export default async function Page() {const data = await getData()return <img src={data[0].url} width="300" />
}
修改revalidatePathTest:
// app/api/revalidatePathTest/route.ts
import { revalidatePath } from 'next/cache'
import { NextRequest } from 'next/server'export async function GET(request: NextRequest) {const tag = request.nextUrl.searchParams.get('tag')revalidateTag(tag)return Response.json({ revalidated: true, now: Date.now() })
}
操作如下:

我们可以发现:
- 当我们多次刷新
http://localhost:3000/,图片并没有改变,因为缓存的作用。 - 当我们访问:
http://localhost:3000/api/revalidatePathTest?tag=refresh,我们带上了指定的tag。值为refresh。 - 此时再次访问首页,发现图片修改。
- 而我们的图片在
fetch的时候,await fetch('https://api.thecatapi.com/v1/images/search', { next: { tags: ['refresh'] } }),指定了tag为refresh - 因此可以联动做到重新验证。
1.3 缓存的退出方式
上面说的都是重新验证,说白了就是缓存的一种刷新机制,那么我们是否有办法主动退出缓存呢?
当使用 fetch 的时候,若满足以下情形,可以做到默认退出缓存机制:
fetch请求添加了cache: 'no-store'或者revalidate: 0属性。例如
fetch('', { cache: 'no-store' })
fetch请求在路由处理程序中并使用了其他方法,例如POST。- 函数体内使用到了
headers或cookies等方法。
export async function GET(request) {const token = request.cookies.get('token')return Response.json({ data: new Date().toLocaleTimeString() })
}
- 配置了路由段选项
const dynamic = 'force-dynamic'
export const dynamic = 'force-dynamic'
- 配置了路由段选项
fetchCache,默认会跳过缓存
二. Server Actions
Server Actions 是指在服务端执行的异步函数,但是可以在服务端和客户端组件中使用。 我们什么情况下可以用到这个呢?
- 在
PageRouter情况下,若需要前后端进行交互,则需要先定义一个接口。 - 在
AppRouter情况下,这种操作则可以简化为Server Actions。我们可以定义一个Server Actions,然后直接在客户端使用获取数据。
它的基本定义方式就是通过 'use server' 声明,一般分为两种:
- 模块级别:在文件的顶部声明,那么该文件下声明的所有导出函数都是
Server Actions。 - 函数级别:在函数内部的顶端添加声明,那么只有该函数是
Server Actions。
例如:
// 函数级别
async function getData() {'use server'// ...
}// 模块级别 app/serverActions/action.ts
'use server'
export async function getData() {// ...
}
export async function create() {// ...
}
2.1 PageRouter下 API 简单案例
我们定义一个接口:

import { NextRequest, NextResponse } from 'next/server'export async function GET(request: NextRequest) {const res = await fetch('https://jsonplaceholder.typicode.com/posts')const data = await res.json()return NextResponse.json(data)
}
然后定义一个页面,通过API的方式从后端取数据。
'use client'import { useEffect, useState } from "react"export default function Page() {const [data, setData] = useState<any>(null)async function getList() {const data = await (await fetch('/api/getData')).json();setData(data);}useEffect(() => {getList();}, [])return (<ul>{data?.map((item: any) => (<li key={item.id}>{item.title}</li>))}</ul>)
}
2.2 AppRouter 下 Server Actions 简单案例
我们来看下使用Server Actions的简单案例,一般我们定义一个actions文件夹:

里面的函数如下:
'use server'
export async function getData() {const res = await fetch('https://jsonplaceholder.typicode.com/posts')const data = await res.json()return data;
}
然后在组件中使用:服务端组件和客户端组件都可以使用
import { getData } from '../actions/actions'export default async function Page() {const data = await getData();return (<ul>{data.map((item: any) => (<li key={item.id}>{item.title}</li>))}</ul>)
}
可以看到Server Actions代码更加简洁,无需手动创建一个接口。并且这个函数可以在代码的任何一个地方使用。
相关文章:
NextJs 数据篇 - 数据获取 | 缓存 | Server Actions
NextJs 数据篇 - 数据获取 | 缓存 | Server Actions 前言一. 数据获取 fetch1.1 缓存 caching① 服务端组件使用fetch② 路由处理器 GET 请求使用fetch 1.2 重新验证 revalidating① 基于时间的重新验证② 按需重新验证revalidatePathrevalidateTag 1.3 缓存的退出方式 二. Ser…...
腾讯开源人像照片生成视频模型V-Express
网址 https://github.com/tencent-ailab/V-Express 下面是github里的翻译: 在人像视频生成领域,使用单张图像生成人像视频变得越来越普遍。一种常见的方法是利用生成模型来增强受控发电的适配器。 但是,控制信号的强度可能会有所不同&…...
pytorch使用DataParallel并行化保存和加载模型(单卡、多卡各种情况讲解)
话不多说,直接进入正题。 !!!不过要注意一点,本文保存模型采用的都是只保存模型参数的情况,而不是保存整个模型的情况。一定要看清楚再用啊! 1 单卡训练,单卡加载 #保存模型 torc…...
PS初级|写在纸上的字怎么抠成透明背景?
前言 上一次咱们讲了很多很多很多的抠图教程,这次继续。。。最近有小伙伴问我:如果是写在纸上的字,要怎么把它抠成透明背景。 这个其实很简单,直接来说就是选择通道来抠。但有一点要注意的是,写在纸上的字࿰…...
Docker面试整理-Docker的网络是如何工作的?
Docker 的网络功能允许容器以多种方式连接到彼此、宿主机以及外部网络。Docker 使用不同的网络驱动来支持这些连接,每种驱动方式都适用于特定的用途。理解 Docker 的网络是如何工作的,可以帮助你更好地设计和管理容器化应用的通信。 Docker 网络驱动 bridge:默认网络驱动。当…...
获得抖音商品评论 API 返回值
公共参数 名称类型必须描述keyString是调用key(获取key和密钥)secretString是调用密钥api_nameString是API接口名称(包括在请求地址中)[item_search,item_get,item_search_shop等]cacheString否[yes,no]默认yes&am…...
Qt | QtBluetooth(蓝牙电脑当服务端+手机当客户端) 配对成功啦
01、前言 没有演示,因为穷,电脑没有带蓝牙,但是已在其他电脑进行演示,可以满足配对,后期再补充和手机进行聊天,如果有聊天的记得私聊我,好处大大滴。02、QtBlueTooth 简介 QtBluetooth 是一个跨平台的蓝牙库,它允许开发者创建在支持蓝牙的设备上运行的应用程序。这个库…...
我找到了全网最低价买服务器的 bug !!!
拍断大腿 周五,放松一下,给大家分享下我最近的事儿,以及带大家薅个(可能会有)的羊毛。 上个月,家里买了 Apple TV(可理解为苹果的电视盒子)装了 infuse(一个在电视盒子上…...
聚类的外部指标(Purity, ARI, NMI, ACC) 和内部指标(NCC,Entropy,Compactness,Silhouette Index)
在聚类分析中,外部指标和内部指标用于评估聚类结果的质量。外部指标需要知道真实的类别标签,而内部指标则仅基于聚类结果本身进行评估。 外部指标 Purity (纯度): 计算聚类结果中每个簇中最多数目的样本所属的类别,并计算所有簇的该类别样本数之和占所有样本数的比例。 Pyt…...
国标GB/T 28181详解:国标GBT28181-2022的客户端主动发起历史视音频回放流程
目录 一、定义 二、作用 1、提供有效的数据回顾机制 2、增强监控系统的功能性 3、保障数据传输与存储的可靠性 4、实现精细化的操作与控制 5、促进监控系统的集成与发展 三、历史视音频回放的基本要求 四、命令流程 1、流程图 2、流程描述 五、协议接口 1、会话控…...
Vue项目安装axios报错npm error code ERESOLVE npm error ERESOLVE could not resolve解决方法
在Vue项目中安装axios时报错 解决方法:在npm命令后面加--legacy-peer-deps 例如:npm install axios --save --legacy-peer-deps 因为别的需求我把node版本重装到了最新版(不知道是不是这个原因),后来在项目中安装axi…...
【Linux】Centos7升级内核的方法:yum更新(ELRepo)
😎 作者介绍:我是程序员洲洲,一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主。 🤓 同时欢迎大家关注其他专栏,我将分享Web前后端开发、人工智能、机器学习、深…...
【CSS】object-fit 和 object-position 属性详解
目录 object-fit属性属性值:使用场景: object-position 属性语法:例如:使用场景: object-fit和object-position是CSS属性,用于控制图像或视频在其容器中的适应和定位方式。 object-fit属性 属性值…...
【算法专题--栈】最小栈--高频面试题(图文详解,小白一看就会!!)
目录 一、前言 二、题目描述 三、解题方法 ⭐解题方法--1 ⭐解题方法--2 四、总结 五、共勉 一、前言 最小栈这道题,可以说是--栈专题--,比较经典的一道题,也是在面试中频率较高的一道题目,通常在面试中,面试官可…...
Vite项目构建chrome extension,实现多入口
本项目使用Vite5 Vue3进行构建。 要使用vite工程构建浏览器插件,无非就是要实现popup页面和options页面。这就需要在项目中用到多入口打包(生成多个html文件)。 实现思路: 通过配置vite工程,使得项目打包后有两个h…...
【vector模拟实现】附加代码讲解
vector模拟实现 一、看源代码简单实现1. push_backcapacity(容量)sizereserve(扩容)operator[ ] (元素访问) 2. pop_back3. itorator(迭代器)4.insert & erase (头插…...
本地运行ChatTTS
TTS 是将文字转为语音的模型,最近很火的开源 TTS 项目,本地可以运行,运行环境 M2 Max,差不多每秒钟 4~~5 个字。本文将介绍如何在本地运行 ChatTTS。 下载源码 首先下载源代码 git clone https://github…...
应用解析 | 面向智能网联汽车的产教融合解决方案
背景介绍 随着科技的飞速发展,智能网联汽车已成为汽车产业的新宠,引领着未来出行的潮流。然而,行业的高速发展也带来了对高素质技术技能人才的迫切需求。为满足这一需求,推动教育链、人才链与产业链、创新链的深度融合࿰…...
华为设备动态路由OSPF(单区域+多区域)实验
动态路由OSPF的配置 OSPF分类两种情况:单区域 多区域路由 OSPF单区域路由配置 OSPF:开放最短路径优先的路由协议。属于大型动态路由协议,适用于中大型的园区网。 网络拓扑: 配置步骤: 1.完成基本配置(略&a…...
R语言探索与分析19-CPI的分析和研究
一、选题背景 CPI(居民消费价格指数)作为一个重要的宏观经济指标,扮演着评估通货膨胀和居民生活水平的关键角色。在湖北省这个经济活跃的地区,CPI的波动对于居民生活、企业经营以及政府宏观经济政策制定都具有重要的影响。因此&a…...
如何在没有计算机的情况下恢复Android上已删除的文件
意外从Android设备中删除重要文件可能会给您带来压力,但了解如何在没有计算机的情况下在Android上恢复已删除的文件可以节省您的时间和麻烦。幸运的是,有多种方法可以直接从手机恢复丢失的数据,无需计算机。从使用“最近删除”文件夹到利用 G…...
手把手教你用SSD2828点亮MIPI屏:从示波器波形到BIST画面的完整调试记录
SSD2828实战调试:从信号分析到MIPI屏幕点亮的全流程解析 当一块MIPI屏幕无法正常点亮时,硬件工程师的调试工作往往从示波器的波形分析开始。本文将基于SSD2828芯片的RGB转MIPI转换板开发经验,详细还原从信号异常到成功显示BIST画面的完整调试…...
深度挖掘显卡潜能:NVIDIA Profile Inspector 高级调优完全指南
深度挖掘显卡潜能:NVIDIA Profile Inspector 高级调优完全指南 【免费下载链接】nvidiaProfileInspector 项目地址: https://gitcode.com/gh_mirrors/nv/nvidiaProfileInspector 你是否曾经对NVIDIA控制面板中有限的设置选项感到不够用?是否想要…...
应届生编程面试,这8个加分项,让你在面试官面前脱颖而出
文章目录前言一、基础扎实:别死背八股,要懂“为什么”1. 经典技术永不过时,别盲目追新2. 把“是什么”变成“为什么”,才是真的懂二、项目经历:不说技术栈,说“解决了什么问题”1. 用数据说话,量…...
揭秘Midjourney底层图像编码协议:Rust逆向解析PNG元数据+动态DPI印相校准(含v6.2协议逆向日志)
更多请点击: https://intelliparadigm.com 第一章:Midjourney图像编码协议的演进与印相范式变革 Midjourney 的图像生成并非基于传统像素栅格的直接操作,而是依托一套动态演化的隐式编码协议——该协议将文本提示(prompt&#x…...
为什么你的ElevenLabs中文输出像机器人?揭秘声学模型对简繁混排、轻声儿化的3层隐式降权机制
更多请点击: https://intelliparadigm.com 第一章:为什么你的ElevenLabs中文输出像机器人?揭秘声学模型对简繁混排、轻声儿化的3层隐式降权机制 ElevenLabs 的 TTS 引擎虽在英文语音合成上表现卓越,但其底层声学模型(…...
SOLID不是教条!DeepSeek检查报告揭示:83%的“违规”实为合理权衡——附5个高可信度豁免决策框架
更多请点击: https://intelliparadigm.com 第一章:SOLID不是教条!DeepSeek检查报告揭示:83%的“违规”实为合理权衡——附5个高可信度豁免决策框架 SOLID原则常被误读为不可逾越的代码铁律,但DeepSeek-R1在对127个中大…...
Windows系统管理终极指南:用WinUtil一键搞定软件安装与系统优化
Windows系统管理终极指南:用WinUtil一键搞定软件安装与系统优化 【免费下载链接】winutil Chris Titus Techs Windows Utility - Install Programs, Tweaks, Fixes, and Updates 项目地址: https://gitcode.com/GitHub_Trending/wi/winutil 你是否曾经花费数…...
【5月最新】小龙虾 AI|Windows 一键部署 + 飞书机器人配置
OpenClaw 2.7.1|Windows 部署 飞书机器人对接全流程教程 本文包含两部分:Windows 一键部署详细步骤 飞书机器人完整配置指南,全程零命令、零复杂配置,新手 10 分钟可完成部署与渠道对接,快速打造可远程操控的 AI 数…...
告别软件模拟!用GD32F303的硬件I2C0读写AT24C02,实测性能提升与资源占用对比
告别软件模拟!用GD32F303的硬件I2C0读写AT24C02,实测性能提升与资源占用对比 在嵌入式开发中,I2C总线作为经典的双线制串行通信协议,被广泛用于连接各类传感器、存储器和外设模块。然而,许多开发者出于快速验证或兼容性…...
