Next.js@14 server actions 使用体验

Next.js Server Actions

Next.js@14 中默认开启 Server Actions

Next.js 先打通了 React 在客户端与服务端“渲染”分界。Server Actions 则打通了客户端与服务端“数据”分界。

渲染分界

客户端与服务端渲染一致,就是常说的 SSR。

数据分界

客户端与服务端之间互通需要一个载体。一般为服务端暴露的一个 http 实现的接口方法,客户端通过 fetch 或 xhr 调用。

使用 server actions 则不需要再关注 http 方法地址与需要接受的数据格式。就像调用本地函数,数据则通过函数的入参传输。不用再关注 http 接口所接受的数据格式与处理返回格式。

虽然 Next.js 在幕后是使用 http 的 post 方法进行传输。就约等于 Next.js 帮我们实现了 http 接口的创建,返回数据处理。重建 Next.js 应用的心智模型。

server actions 因为服务端不再暴露 http 的方法接口地址,只有该 server actions 函数能进行数据的调用。并且返回的数据结构为 React 流(参考文档)。虽然可以通过手动添加 http request header Next-Action 属性来达到伪造请求。但一定程度上迷惑破译者。

官方解释

Behavior

  • Server actions can be invoked using the action attribute in a <form> element:
    • Server Components support progressive enhancement by default, meaning the form will be submitted even if JavaScript hasn't loaded yet or is disabled.
    • In Client Components, forms invoking Server Actions will queue submissions if JavaScript isn't loaded yet, prioritizing client hydration.
    • After hydration, the browser does not refresh on form submission.
  • Server Actions are not limited to <form> and can be invoked from event handlers, useEffect, third-party libraries, and other form elements like <button>.
  • Server Actions integrate with the Next.js caching and revalidation architecture. When an action is invoked, Next.js can return both the updated UI and new data in a single server roundtrip.
  • Behind the scenes, actions use the POST method, and only this HTTP method can invoke them.
  • The arguments and return value of Server Actions must be serializable by React. See the React docs for a list of serializable arguments and values.
  • Server Actions are functions. This means they can be reused anywhere in your application.
  • Server Actions inherit the runtime from the page or layout they are used on.

体验

在使用 Next.js 开发文件管理系统时,去掉了客户端调用 http 接口的封装过程。例如接口新增参数、减少参数,改变返回类型等对接口进行更改时,借助 TypeScript 或者 JSDoc 的类型描述则可有较好的开发提示。

可以直接通过 server actions 调用 node.js 的 fs 下的方法。也就是老被吐槽的,可能会自己干掉自己。

删除方法

'use server'
import fs from 'fs'

export const del = () => {
  fs.rmSync('/')
}

调用删除方法

'use client'
import { del } from './del'

export function DelBtn() {
    return <button onClick={() => del()}/>
}

客户端组件可以用在任何地方进行调用,例如组件初始化、销毁;各种 dom 事件。

Server Actions 调用时返回一个 Promise,所以可以结合使用 ahooksuseRequest 或者 swr 提升数据消费体验。例如常用的“缓存”、“屏幕聚焦重新请求”等功能。

并不是 Next.js 不再需要 http 的接口了。例如实现自己的流式传输数据时还是需要 http 接口的。例如图片文件的查看、下载文件内容,上传文件等操作。

默认情况下 Server Actions 的 body 大小为 1mb。可通过修改 bodysizelimit 参数增加或减少。

next.config.js

/** @type {import('next').NextConfig} */
 
module.exports = {
  experimental: {
    serverActions: {
      bodySizeLimit: '2mb',
    },
  },
}

调用截图

当鼠标 hover 到顶部面包屑导航时,出现当前选中目录下所有文件夹的下拉菜单。使用 Server Actions 获取菜单内容。

截屏2023-12-26 12.59.57.png

请求载荷

[
    {
        "path": "/Downloads/ways",
        "only_dir": "1",
        "has_file_stat": "1"
    }
]

响应

0:["$@1",["development",null]]
1:[{"name":"JPG2","is_directory":true,"stat":{"dev":16777220,"mode":16877,"nlink":3,"uid":501,"gid":20,"rdev":0,"blksize":4096,"ino":120655456,"size":96,"blocks":0,"atimeMs":1703242044321.7495,"mtimeMs":1703242019496.5264,"ctimeMs":1703242044324.9827,"birthtimeMs":1703242019496.5264,"atime":"$D2023-12-22T10:47:24.322Z","mtime":"$D2023-12-22T10:46:59.497Z","ctime":"$D2023-12-22T10:47:24.325Z","birthtime":"$D2023-12-22T10:46:59.497Z"}},]

伪造 fetch 请求,会发现返回当前页面,而不是数据。

截屏2023-12-26 13.42.31.png

request headers

POST /path/Downloads/ways/PSD HTTP/1.1
Accept: text/x-component
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8,en-US;q=0.7,en;q=0.6
Connection: keep-alive
Content-Length: 63
Content-Type: text/plain;charset=UTF-8
Cookie: readdir-sort=desc_date; display-type=card; card-column=3; window=%257B%2522width%2522%253A747%252C%2522height%2522%253A1122%257D; viewport-size={%22width%22:747%2C%22height%22:1122}
DNT: 1
Host: localhost:3000
Next-Action: 706aae5c02f31f5f481711066003ad67eeb6dc82
Next-Router-State-Tree: %5B%22%22%2C%7B%22children%22%3A%5B%22path%22%2C%7B%22children%22%3A%5B%5B%22path%22%2C%22Downloads%2Fways%2FPSD%22%2C%22oc%22%5D%2C%7B%22children%22%3A%5B%22__PAGE__%22%2C%7B%7D%5D%7D%5D%7D%5D%7D%2Cnull%2Cnull%2Ctrue%5D
Origin: http://localhost:3000
Referer: http://localhost:3000/path/Downloads/ways/PSD
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
sec-ch-ua: "Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"

通过分析 http request headers,Server Actions 在 header 中插入了下面的关属性。

...
Next-Action: 706aae5c02f31f5f481711066003ad67eeb6dc82
...

fetch 主动将该值插入 headers 内则可手动成功调用 Server Actions。

fetch('/path/Downloads/ways/PSD', {method:'POST', headers:{'Next-Action':'706aae5c02f31f5f481711066003ad67eeb6dc82'}, body: JSON.stringify([{path: "", only_dir: "1", has_file_stat: "1"}])})

使用开发工具搜索 706aae5c02f31f5f481711066003ad67eeb6dc82 关键词,发现如下结果

截屏2023-12-26 13.51.03.png

生产环境下则为被压缩混淆

截屏2023-12-26 13.53.31.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,640评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,254评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,011评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,755评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,774评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,610评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,352评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,257评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,717评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,894评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,021评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,735评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,354评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,936评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,054评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,224评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,974评论 2 355

推荐阅读更多精彩内容