NextJS 13 AppDir:如何实现服务器端获取数据的搜索筛选?
在Next.js 13 App Dir中实现服务器端数据的搜索筛选
核心结论
服务器组件完全可以访问URL的Search Params,这是实现服务器端数据筛选的标准方案,既安全又符合App Dir的架构设计。
服务器端能访问的内容
在App Dir的服务器组件中,你可以直接获取:
- 组件props中的
searchParams(URL查询参数) cookies(通过cookies()函数)- 请求头(通过
headers()函数) - 路径参数(比如
/posts/[id]中的id)
这些信息都是服务器端处理的,不会暴露给客户端,敏感凭证(如Bearer Token)可以存在服务器环境变量中,无需让客户端接触。
实现步骤
1. 客户端搜索组件(处理输入并更新Search Params)
因为需要处理输入状态,搜索栏必须是客户端组件(加'use client'指令),它的作用只是更新URL的搜索参数,不直接请求数据:
'use client'; import { useRouter } from 'next/navigation'; import { useState } from 'react'; export default function SearchBar() { const [query, setQuery] = useState(''); const router = useRouter(); const handleSearch = (e: React.FormEvent) => { e.preventDefault(); // 更新URL的search params,触发服务器组件重新渲染 router.push(`/?search=${encodeURIComponent(query)}`); }; return ( <form onSubmit={handleSearch}> <input type="text" value={query} onChange={(e) => setQuery(e.target.value)} placeholder="搜索..." /> <button type="submit">搜索</button> </form> ); }
2. 服务器页面组件(接收参数并筛选数据)
服务器组件通过props获取searchParams,用这个参数去调用后端API(服务器端调用,凭证存在环境变量):
import SearchBar from './SearchBar'; // 服务器组件,自动接收searchParams props export default async function Home({ searchParams }: { searchParams: { search?: string } }) { const searchQuery = searchParams.search || ''; // 服务器端调用后端API,使用环境变量中的凭证 const res = await fetch(`https://your-api.com/data?search=${encodeURIComponent(searchQuery)}`, { headers: { Authorization: `Bearer ${process.env.API_TOKEN}`, // 这个token存在服务器环境变量,客户端看不到 }, }); const data = await res.json(); return ( <div> <SearchBar /> <ul> {data.map((item: any) => ( <li key={item.id}>{item.name}</li> ))} </ul> </div> ); }
为什么客户端直接请求不安全?
如果在客户端直接调用后端API,你必须把Bearer Token暴露在客户端代码中(哪怕存在NEXT_PUBLIC_环境变量,也会被打包到客户端JS里),攻击者可以轻松获取这个token并冒充用户请求API。而通过服务器端代理请求,token只存在服务器环境中,客户端完全接触不到,安全性大幅提升。
其他可选方案:表单POST提交
如果不想用URL参数(比如搜索内容敏感),可以用App Dir的服务器Action处理表单提交:
'use client'; import { useFormState } from 'react-dom'; import { searchAction } from './actions'; export default function SearchBar() { const [state, formAction] = useFormState(searchAction, null); return ( <form action={formAction}> <input type="text" name="search" placeholder="搜索..." /> <button type="submit">搜索</button> </form> ); }
对应的服务器Action:
'use server'; export async function searchAction(prevState: any, formData: FormData) { const searchQuery = formData.get('search') as string; // 服务器端调用API,逻辑和之前一致 const res = await fetch(`https://your-api.com/data?search=${encodeURIComponent(searchQuery)}`, { headers: { Authorization: `Bearer ${process.env.API_TOKEN}`, }, }); const data = await res.json(); return data; }
然后在服务器组件中使用这个Action的结果即可。
内容的提问来源于stack exchange,提问作者Arinautic
相关产品推荐
相关产品推荐

