获取查询参数(Next.js 服务器组件)
问题
在 Next.js 13 中引入了全新的 app
目录架构,组件默认成为"服务器组件"(Server Components)。这些组件具有特殊能力:
- 支持
async/await
执行异步操作 - 可直接访问
cookies()
获取 Cookie - 可直接访问
headers()
获取请求头
但官方文档未说明如何直接在服务器组件中获取 URL 查询参数(query params)。在 Next.js 13 之前的 getServerSideProps
方法中,可通过 context.query
轻松访问查询参数,但在新的服务器组件架构中,这一常用功能如何实现?
解决方案
方法一:在页面组件中直接获取 (推荐)
在 app
目录下的页面文件(page.tsx/page.jsx
)中,Next.js 会自动提供 searchParams
属性:
tsx
export default function Page({
searchParams,
}: {
searchParams?: { [key: string]: string | string[] | undefined };
}) {
// 获取查询参数
const filter = searchParams?.filter;
const page = searchParams?.page;
return (
<div>
<h1>筛选器:{filter}</h1>
<p>页码:{page || 1}</p>
</div>
);
}
- 访问方式:
searchParams?.参数名
(可选链避免未定义错误) - 参数值类型:
string | string[] | undefined
- 适用场景:页面级组件获取 URL 参数
- 优势:官方推荐方式,简洁直接
方法二:在 API 路由中获取
在 app/api
目录下的路由处理器(route.ts/route.js
)中处理请求时:
ts
export async function GET(request: Request) {
// 解析URL参数
const { searchParams } = new URL(request.url);
// 获取具体参数值
const skip = searchParams.get("skip")
const limit = searchParams.get("limit")
// 使用参数处理业务逻辑
return new Response(JSON.stringify({ skip, limit }), {
status: 200,
headers: { "Content-Type": "application/json" }
});
}
- 访问方式:
new URL(request.url).searchParams
- 参数方法:
get()
:获取单个参数getAll()
:获取数组类型参数entries()
:遍历所有参数
- 适用场景:API 路由处理程序
方法三:在组件中获取路径参数
访问动态路由中的路径参数(如 app/category/[filter]/page.tsx
):
tsx
const Page = async ({
params,
searchParams
}: {
params: { filter: string };
searchParams: { [key: string]: string | string[] | undefined };
}) => {
// 路径参数 - 来自 segment
const filter = params.filter;
// 查询参数 - 来自 URL
const page = searchParams.page;
return (
<div>
<h2>路径参数:{filter}</h2>
<p>查询参数:{page}</p>
</div>
)
}
方法四:通过中间件全局传递(任意组件)
TIP
当需要在非页面组件中访问查询参数时,可通过中间件全局传递
- 创建中间件(
middleware.ts
):
ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// 将完整URL存入请求头
const headers = new Headers(request.headers);
headers.set('x-url', request.url);
return NextResponse.next({ request: { headers } });
}
- 在任意服务器组件中使用:
tsx
import { headers } from 'next/headers';
export default function ProductList() {
// 从header获取存储的URL
const headerList = headers();
const fullUrl = headerList.get('x-url') || '';
// 解析查询参数
const url = new URL(fullUrl);
const minPrice = url.searchParams.get('min_price');
return (
<div>
筛选的价格下限:{minPrice}
</div>
);
}
常见错误解决方案
错误:searchParams is undefined
tsx
// 错误情况:未正确声明类型
export default function Page({ searchParams }) { /* ... */ }
✅ 解决方案: 明确声明类型
tsx
export default function Page({
searchParams
}: {
searchParams?: { [key: string]: string | string[] | undefined };
}) {
// ...
}
最佳实践建议
优先选择在页面组件获取:
- 适用于大多数场景
- 避免过度设计
安全注意:
tsx<div dangerouslySetInnerHTML={{ __html: searchParams.unsafe }} />
- 禁止直接渲染未处理的查询参数内容
- 应对参数值进行安全过滤
参数格式处理:
tsxconst page = parseInt(searchParams?.page as string || '1')
- 数字参数需显式类型转换
- 设置合理的参数默认值
总结
场景 | 推荐方法 | 示例代码 |
---|---|---|
页面组件获取查询参数 | searchParams 属性 | export default Page({ searchParams }) |
API路由获取查询参数 | URL 和 URLSearchParams | new URL(request.url).searchParams |
获取动态路由路径参数 | params 属性 | export default Page({ params }) |
任意组件参数访问 | 中间件+请求头传递 | 见"方法四"详细实现 |
:::success 最佳实践建议:优先使用页面组件自带的 searchParams
属性获取查询参数,只有在特殊情况下才采用中间件等复杂方案 :::