配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 > ;