Next.js 技术总结:Server Action vs Route Handler? client Fetch vs server Fetch?
<h2>一、原生Client Fetch vs Server Fetch 的差异</h2><table>
<thead>
<tr><th>对比点</th><th>Client Fetch(浏览器)</th><th>Server Fetch(服务端)</th></tr>
</thead>
<tbody>
<tr>
<td>🔐 Cookie 携带方式</td>
<td>
<p>理论:默认自动携带(同源),跨域需 <code>credentials: 'include'</code></p>
<p>实际:same-origin 使用 <code>credentials: 'include </code></p>
<p><理由详见 Token文章></p>
</td>
<td>
<p>理论:❌ 不自动携带,<strong>必须手动将 <code>Cookie</code> 放入 headers</strong></p>
<p>实际:语义不正确,server fetch只用Authorization</p>
<p><理由详见 Token文章></p>
</td>
</tr>
<tr>
<td>🌐 路径补全</td>
<td>✅ 支持相对路径,会自动补全为当前 origin</td>
<td>❌ 不支持相对路径,<strong>必须写完整绝对路径</strong>(带协议和域名)</td>
</tr>
<tr>
<td>🎯 运行上下文</td>
<td>有页面上下文(host、用户、location)</td>
<td>没有上下文,必须开发者显式提供; fetch是纯函数环境</td>
</tr>
<tr>
<td>⚙️ 可设置缓存行为</td>
<td>cache: 'force-cache' | 'no-store'</td>
<td>❌ no cache </td>
</tr>
</tbody>
</table>
<h2>二、NextJS fetch 增强点:只增强server fetch!</h2>
<p>Server fetch 增强点</p>
<p>1. 相对路径自动补全,执行route handler, 不发送真实网络请求!</p>
<p>2. <code data-start="509" data-end="526">next.revalidate</code> 是服务端编译阶段用于构建 <strong data-start="540" data-end="553">ISR 缓存依赖图</strong> 的指令</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">next: {
revalidate: </span>60, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ISR 缓存秒数</span>
tags: ['product'], <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ISR 依赖标记</span>
}</pre>
</div>
<p>3. 控制 SSR cache</p>
<p>cache: 'no-store' </p>
<p> </p>
<hr>
<p> </p>
<p> </p>
<h2>三、Server Action vs Route Handler</h2>
<h3>✅ Route Handler (<code data-start="1096" data-end="1119">/app/api/xxx/route.ts</code>)</h3>
<ul>
<li>更适合做 <strong data-start="1179" data-end="1193">查询类 GET 请求</strong>,比如获取当前登录用户、拉取商品列表;</li>
<li>可以配置 <strong data-start="1220" data-end="1228">缓存机制</strong>(如 <code data-start="1231" data-end="1243">revalidate</code>、ISR、SWR 等),具有<strong data-start="1257" data-end="1265">高可控性</strong>;</li>
</ul>
<h3>✅ Server Action (<code data-start="1340" data-end="1351">action.ts</code>)</h3>
<ul>
<li>更适合做 <strong data-start="1465" data-end="1476">带副作用的修改行为</strong>,比如:提交表单、写数据库、修改状态;</li>
<li>❌ 不支持缓存。如果强行使用页配置const revalidate = 30,该缓存设置会自动作废。</li>
</ul>
<p data-start="1376" data-end="1382">必须运行在:</p>
<ul data-start="1385" data-end="1457">
<li data-start="1385" data-end="1411">
<p data-start="1387" data-end="1411">Server Component 内部直接调用;</p>
</li>
<li data-start="1414" data-end="1457">
<p data-start="1416" data-end="1457">或 <code data-start="1418" data-end="1446"><form action={yourAction}></code> 中由浏览器发起提交;</p>
</li>
</ul>
<table>
<thead>
<tr><th>使用场景</th><th>推荐方案</th></tr>
</thead>
<tbody>
<tr>
<td>获取登录状态 / 查询商品</td>
<td>✅ Route Handler + <code>fetch</code>(可缓存、可重用)</td>
</tr>
<tr>
<td>用户注册 / 提交订单 / 表单行为</td>
<td>✅ Server Action(组件内直接调用)</td>
</tr>
<tr>
<td>通用 API 服务(第三方调用)</td>
<td>✅ Route Handler</td>
</tr>
<tr>
<td>后台管理系统的按钮操作</td>
<td>✅ Client fetch + Route Handler 或 <code><form action={}</code> + Server Action</td>
</tr>
</tbody>
</table>
<h1>总结</h1>
<p><strong><span style="color: rgba(153, 51, 102, 1); font-size: 18pt">server action</span></strong> <br>来源于:RSC or client Comp <form> submittion<br> 那么是否可以来源于Route handler? 答:build-time!需要编译!<br>适用于:执行“副作用”行为。 不可以缓存!<br>是否能await cookie or headers? ❌ 由于是直接调用方法而来,不会携带,所以不能</p>
<p><span style="font-size: 18pt"><strong><span style="color: rgba(153, 51, 102, 1)">route handler</span></strong></span> <br>来源于:client or server Fetch <br>适用于:查询方法<br>假网络通信, 所以可以使用await cookie(),等同于req.cookie接受传递的cookie<br> 本质:cookies() 是对 req.headers.get('cookie') 的进一步封装</p>
<p>第一个参数是req,第二个参数可以是{ params } : { params: { tenantId: string } } 获得动态参数</p>
<p><span style="font-size: 18pt"><strong><span style="color: rgba(153, 51, 102, 1)">SSR: RSC</span></strong></span><br>来源于: hard nav or soft nav <br>接受hard nav/ soft nav自动携带的 cookie、headers: await cookie/headers <br>用于查询注入client comp,<br> 1. 选择server fetch+单条revalidate: <br> 坏处:额外await cookie,塞入headers传递<br> 好处:控制细粒度revalidate<br> 2.选择页面级revalidate+async function <br> 好处:直接await cookies() 直接拿来就用,✅ 更适合大多数场景</p>
<p><span style="font-size: 18pt"><strong><span style="color: rgba(153, 51, 102, 1)">nextjs-client fetch</span></strong></span> <br>相对路径自动补全<br>cookie:credentials:'include'用于同源<br>cache: 可;默认是 no-store<br>ISR: ❌ 比如客户端发起client fetch,是否能每隔30秒重新发起,<br> 不行,因为是ISR是编译行为,<br> Client fetch 是运行时行为,不受 ISR 控制。<br>token:同源用HttpOnly cookie+credentials,跨源用headers:Authentication: Bearer Token</p>
<p><span style="font-size: 18pt"><strong><span style="color: rgba(153, 51, 102, 1)">nextjs-server fetch</span></strong></span> <br>相对路径自动补全<br>cache: 可以cache <br>ISR: revalidate可多组件复用缓存; 注意使用的时候搭配上page revalidate是最佳实践<br>cookie:headers中设置cookie。 <br>token:同源用cookie,跨源用headers:Authentication</p>
<p><span style="font-size: 18pt"><strong><span style="color: rgba(153, 51, 102, 1)">hard nav</span></strong></span><br>来源于:刷新 or URL address input<br>cookie:自动携带same site cookie; 只要不是 SameSite=Strict <br>headers:携带来自浏览器 or mobile or IP 包括 UA、Accept-Language、Referer 等</p>
<p><span style="font-size: 18pt"><strong><span style="color: rgba(153, 51, 102, 1)">soft nav</span></strong></span> <br>来源于: <Link> or useRouter().push or redirect <br>cookie:自动携带same site cookie <br>headers:携带什么?❌ 没有</p>
<p> </p><br><br>
来源:https://www.cnblogs.com/sabertobih/p/18962671
頁:
[1]