路由处理程序是指使用WebRequest和ResponseAPI对于给定的路由自定义处理逻辑。简单来说,前后端分离架构中,客户端与服务端之间通过API接口来交互。这个API接口在Next.js中有个更为正式的称呼,就是路由处理程序。
路由处理程序是指使用 Web Request 和 Response API 对于给定的路由自定义处理逻辑。
简单来说,前后端分离架构中,客户端与服务端之间通过 API 接口来交互。这个API 接口在 Next.js 中有个更为正式的称呼,就是路由处理程序。
本篇我们会讲解如何定义一个路由处理程序以及写路由处理程序时常遇到的一些问题。
写路由处理程序,你需要定义一个名为 route.js
的特殊文件。(注意是 route
不是 router
)
该文件必须在 app
目录下,可以在 app
嵌套的文件夹下,但是要注意 page.js
和 route.js
不能在同一层级同时存在。
想想也能理解,page.js
和 route.js
本质上都是对路由的响应。page.js
主要负责渲染 UI,route.js
主要负责处理请求。如果同时存在,Next.js 就不知道用谁的逻辑了。
让我们从写 GET 请求开始,比如写一个获取文章列表的接口。
新建 app/api/posts/route.js
文件,代码如下:
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/posts
查看接口返回的数据:
在这个例子中:
export
一个名为 GET
的 async
函数来定义 GET 请求处理,注意是 export 而不是 export defaultnext/server
的 NextResponse 对象用于设置响应内容,但这里不一定非要用 NextResponse
,直接使用 Response
也是可以的:export async function GET() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts')
const data = await res.json()
return Response.json({ data })
}
但在实际开发中,推荐使用 NextResponse
,因为它是 Next.js 基于 Response
的封装,它对 TypeScript 更加友好,同时提供了更为方便的用法,比如获取 Cookie 等。
app/api
文件夹下,并不是因为接口一定要放在名为 api
文件夹下(与 Pages Router 不同)。如果你代码写在 app/posts/route.js
,对应的接口地址就是 /posts
。放在 api
文件夹下只是为了方便区分地址是接口还是页面。Next.js 支持 GET
、POST
、PUT
、PATCH
、DELETE
、HEAD
和 OPTIONS
这些 HTTP 请求方法。如果传入了不支持的请求方法,Next.js 会返回 405 Method Not Allowed
。
// route.js
export async function GET(request) {}
export async function HEAD(request) {}
export async function POST(request) {}
export async function PUT(request) {}
export async function DELETE(request) {}
export async function PATCH(request) {}
// 如果 `OPTIONS` 没有定义, Next.js 会自动实现 `OPTIONS`
export async function OPTIONS(request) {}
现在让我们再写一个 POST 请求练练手。
继续修改 app/api/posts/route.js
,添加代码如下:
import { NextResponse } from 'next/server'
export async function POST(request) {
const article = await request.json()
return NextResponse.json({
id: Math.random().toString(36).slice(-8),
data: article
}, { status: 201 })
}
现在让我们用接口请求工具调用一下:
现在让我们具体看下请求方法。每个请求方法的处理函数会被传入两个参数,一个 request
,一个 context
。两个参数都是可选的:
export async function GET(request, context) {}
request 对象是一个 NextRequest 对象,它是基于 Web Request API 的扩展。使用 request ,你可以快捷读取 cookies 和处理 URL。
我们这里讲讲如何获取 URL 参数:
export async function GET(request, context) {
// 访问 /home, pathname 的值为 /home
const pathname = request.nextUrl.pathname
// 访问 /home?name=lee, searchParams 的值为 { 'name': 'lee' }
const searchParams = request.nextUrl.searchParams
}
其中 nextUrl 是基于 Web URL API 的扩展(如果你想获取其他值,参考 URL API,同样提供了一些方便使用的方法。
目前context
只有一个值就是 params
,它是一个包含当前动态路由参数的对象。举个例子:
// app/dashboard/[team]/route.js
export async function GET(request, { params }) {
const team = params.team
}
当访问 /dashboard/1
时,params 的值为 { team: '1' }
。其他情况还有:
注意第二行:此时 params 返回了当前链接所有的动态路由参数。
现在让我们写个 demo 复习下这些知识。
需求:目前 GET 请求 /api/posts
时会返回所有文章数据,现在希望 GET 请求 /api/posts/1?dataField=title
获取 post id 为 1 的文章数据,dataField 用于指定返回哪些字段数据。
让我们开始写吧。新建 /api/posts/[id]/route.js
,代码如下:
import { NextResponse } from 'next/server'
export async function GET(request, { params }) {
const field = request.nextUrl.searchParams.get("dataField")
const data = await ((await fetch(`https://jsonplaceholder.typicode.com/posts/${params.id}`)).json())
const result = field ? { [field]: data[field] } : data
return NextResponse.json(result)
}
用接口测试工具测试一下,如果请求地址是 http://localhost:3000/api/posts/1?dataField=title
,效果如下:
如果请求地址是 http://localhost:3000/api/posts/1
,效果如下:
默认情况下,使用 Response
对象(NextResponse
也是一样的)的 GET 请求会被缓存。
让我们举个例子,新建 app/api/time/route.js
,代码如下:
export async function GET() {
console.log('GET /api/time')
return Response.json({ data: new Date().toLocaleTimeString() })
}
注意:在开发模式下,并不会被缓存,每次刷新时间都会改变,现在我们部署生产版本,运行 npm run build && npm run start
:
你会发现,无论怎么刷新,时间都不会改变。这就是被缓存了。
可是为什么呢?Next.js 是怎么实现的呢?
让我们看下构建(npm run build)时的命令行输出:
根据输出的结果,你会发现 /api/time
是静态的,也就是被预渲染为静态的内容,换言之,/api/time
的返回结果其实在构建的时候就已经确定了,而不是在第一次请求的时候才确定。
但大家也不用担心默认缓存带来的影响。实际上,默认缓存的条件是非常“严苛”的,这些情况都会导致退出缓存:
GET
请求使用 Request
对象修改 app/api/time/route.js
,代码如下:
export async function GET(request) {
const searchParams = request.nextUrl.searchParams
return Response.json({ data: new Date().toLocaleTimeString(), params: searchParams.toString() })
}
现在我们部署生产版本,运行 npm run build && npm run start
:
此时会动态渲染,也就是在请求的时...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!