配x 该库的编写是为了支持使用Next.js页面路由器的API路由。它尚未使用应用程序路由器进行测试。
Next.js API路由是一种可笑的有趣而简单的方法,可以将后端功能添加到React应用程序中。但是,当需要添加中间件时,就没有简单的方法来实施它。
Next.JS文档建议在API路由处理程序中写下功能。与Express.js或Koa.js提供的干净API相比,这是巨大的一步。
该图书馆试图提供最小,干净,可组合的中间件模式,既有生产力又令人愉悦。
labeluse import { label , Middleware } from "next-api-middleware" ;
import * as Sentry from "@sentry/nextjs" ;
import nanoid from "nanoid" ;
// 1 – Create middleware functions
const captureErrors : Middleware = async ( req , res , next ) => {
try {
// Catch any errors that are thrown in remaining
// middleware and the API route handler
await next ( ) ;
} catch ( err ) {
const eventId = Sentry . captureException ( err ) ;
res . status ( 500 ) ;
res . json ( { error : err } ) ;
}
} ;
const addRequestId : Middleware = async ( req , res , next ) => {
// Let remaining middleware and API route execute
await next ( ) ;
// Apply header
res . setHeader ( "X-Response-ID" , nanoid ( ) ) ;
} ;
// 2 – Use `label` to assemble all middleware
const withMiddleware = label (
{
addRequestId ,
sentry : captureErrors , // <-- Optionally alias middleware
} ,
[ "sentry" ] // <-- Provide a list of middleware to call automatically
) ;
// 3 – Define your API route handler
const apiRouteHandler = async ( req , res ) => {
res . status ( 200 ) ;
res . send ( "Hello world!" ) ;
} ;
// 4 – Choose middleware to invoke for this API route
export default withMiddleware ( "addRequestId" ) ( apiRouteHandler ) ; 我关于该图书馆如何处理中间件功能的心理模型是“蜿蜒和放松的堆栈”。
让我们想象您已经使用label将两个中间件功能添加到API路由。
当请求进来时,这是对该请求如何通过所有中间件功能,API路由处理程序本身进行的粗略印象,然后通过中间件备份。
|-----------------|-----------------|--------------------|
| Middleware #1 | Middleware #2 | API Route Handler |
|-----------------|-----------------|--------------------|
| | | |
Request ------|----> Setup -----|----> Setup -----|-->------| |
| | | | |
|-----------------|-----------------| V |
| | | |
| await next() | await next() | API stuff |
| | | |
|-----------------|-----------------| | |
| | | | |
Response <----|--- Teardown <---|--- Teardown <---|---------| |
| | | |
|-----------------|-----------------|--------------------|
虽然这是一个crummy ascii图,但我认为这给人留下了正确的印象。该请求随着每个中间件功能的连续功能而缠绕,击中了API路由处理程序,然后通过堆栈“放松”。
每个中间件功能都有机会经历三个阶段:
“设置”阶段涵盖了await next()之前发生的一切。 “等待”阶段实际上只是await next() 。 “拆卸”阶段是await next()之后的中间件功能中的剩余代码。
值得注意的是,尽管这些阶段可用于所有中间件功能,但您不需要利用所有阶段。
例如,在捕获中间件的错误中,您可能只需将await next()包装在try / catch块中。另一方面,您可能会请求定时中间件,该中间件在设置阶段捕获开始时间,等待,然后在拆卸阶段捕获完成时间。
label这是创建可重复使用的中间件集合的主要实用程序。
const withMiddleware = label ( middleware , defaults ) ; middleware :包含中间件功能或中间件数组的对象defaults :(可选)将自动调用的middleware密钥数组label返回一个函数(通常称为withMiddleware ),该功能使用咖喱来接受要调用的中间件名称列表,然后是Next.js API处理程序功能。
通常,将withMiddleware导入API路由文件,并在默认导出语句中使用:
import { withMiddleware } from "../helpers/my-middleware" ;
const apiRouteHandler = async ( req , res ) => {
...
}
export default withMiddleware ( "foo" , "bar" , "baz" ) ( apiRouteHandler ) ;尽管label可能包含许多中间件功能,但API路由所调用的实际中间件由传递给withMiddleware名称确定。
const logErrors = async ( req , res , next ) => {
try {
await next ( ) ;
} catch ( error ) {
console . error ( error ) ;
res . status ( 500 ) ;
res . json ( { error } ) ;
}
} ;
const withMiddleware = label ( {
logErrors ,
} ) ;
// export default withMiddleware("logErrors")(apiRouteHandler); const withMiddleware = label ( {
error : logErrors ,
} ) ;
// export default withMiddleware("error")(apiRouteHandler); import { foo , bar , baz } from "./my-middleware" ;
const withMiddleware = label ( {
error : logErrors ,
myGroup : [ foo , bar , baz ] ,
} ) ;
// export default withMiddleware("error", "myGroup")(apiRouteHandler); const withMiddleware = label (
{
error : logErrors ,
myGroup : [ foo , bar , baz ] ,
} ,
[ "error" ]
) ;
// export default withMiddleware("myGroup")(apiRouteHandler);use该实用程序直接接受中间件功能并按顺序执行所有功能。这是label的更简单的替代方法,可用于处理一次性中间件功能。
const withInlineMiddleware = use ( ... middleware ) ; middleware :中间件功能的列表和/或中间件功能的数组use返回接受Next.js API路由处理程序的函数。
import { use } from "next-api-middleware" ;
import cors from "cors" ;
const apiRouteThatOnlyNeedsCORS = async ( req , res ) => {
...
}
export default use ( cors ( ) ) ( apiRouteThatOnlyNeedsCORS ) ; 有关label和use的更详细的示例,请参见示例.md。
由于use和label接受评估中间件功能的值,因此提供了创建自定义中间件工厂的机会。
这是一个生成中间件功能的工厂的示例,仅允许使用给定的HTTP方法的请求:
import { Middleware } from "next-api-middleware" ;
const httpMethod = (
allowedHttpMethod : "GET" | "POST" | "PATCH"
) : Middleware => {
return async function ( req , res , next ) {
if ( req . method === allowedHttpMethod || req . method == "OPTIONS" ) {
await next ( ) ;
} else {
res . status ( 404 ) ;
res . end ( ) ;
}
} ;
} ;
export const postRequestsOnlyMiddleware = httpMethod ( "POST" ) ;Middleware灵感来自于KOA.J.普及的异型中间件样式。
type Middleware < Request = NextApiRequest , Response = NextApiResponse > = (
req : Request ,
res : Response ,
next : ( ) => Promise < void >
) => Promise < void > ;