跳到主要內容

中介層

警告

已棄用:中介層已在 4.16.0 版本中棄用。

我們建議使用 Prisma Client 擴充功能 query 元件類型 作為中介層的替代方案。Prisma Client 擴充功能首次在 4.7.0 版本中以預覽形式推出,並在 4.16.0 版本中正式發布。

Prisma Client 擴充功能讓您可以建立獨立的 Prisma Client 實例,並將每個用戶端綁定到特定的篩選器或使用者。例如,您可以將用戶端綁定到特定使用者以提供使用者隔離。Prisma Client 擴充功能也提供端對端類型安全。

中介層充當查詢層級的生命週期掛鉤,讓您可以在查詢執行之前或之後執行動作。使用 prisma.$use 方法來新增中介層,如下所示

const prisma = new PrismaClient()

// Middleware 1
prisma.$use(async (params, next) => {
// Manipulate params here
const result = await next(params)
// See results here
return result
})

// Middleware 2
prisma.$use(async (params, next) => {
// Manipulate params here
const result = await next(params)
// See results here
return result
})

// Queries here
警告

當使用 批次交易 時,請勿在中介層中多次調用 next。這會導致您跳出交易並導致意外結果。

params 代表中介層中可用的參數,例如查詢的名稱,而 next 代表 堆疊中的下一個中介層原始 Prisma Client 查詢

中介層的可能用例包括

中介層還有許多其他用例 - 此列表旨在為中介層旨在解決的問題類型提供靈感。

範例

以下範例情境展示如何在實務中使用中介層

在哪裡新增中介層

請求處理程式的上下文之外新增 Prisma Client 中介層,否則每個請求都會將中介層的新實例新增到堆疊中。以下範例示範如何在 Express 應用程式的上下文中新增 Prisma Client 中介層

import express from 'express'
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

prisma.$use(async (params, next) => {
// Manipulate params here
const result = await next(params)
// See results here
return result
})

const app = express()
app.get('/feed', async (req, res) => {
// NO MIDDLEWARE HERE
const posts = await prisma.post.findMany({
where: { published: true },
include: { author: true },
})
res.json(posts)
})

執行順序與中介層堆疊

如果您有多個中介層,則每個獨立查詢的執行順序為

  1. 每個中介層中 await next(params) 之前的所有邏輯,依遞減順序
  2. 每個中介層中 await next(params) 之後的所有邏輯,依遞增順序

根據您在堆疊中的位置,await next(params) 要么

  • 執行下一個中介層(在範例中的中介層 #1 和 #2 中)
  • 執行原始 Prisma Client 查詢(在中介層 #3 中)
const prisma = new PrismaClient()

// Middleware 1
prisma.$use(async (params, next) => {
console.log(params.args.data.title)
console.log('1')
const result = await next(params)
console.log('6')
return result
})

// Middleware 2
prisma.$use(async (params, next) => {
console.log('2')
const result = await next(params)
console.log('5')
return result
})

// Middleware 3
prisma.$use(async (params, next) => {
console.log('3')
const result = await next(params)
console.log('4')
return result
})

const create = await prisma.post.create({
data: {
title: 'Welcome to Prisma Day 2020',
},
})

const create2 = await prisma.post.create({
data: {
title: 'How to Prisma!',
},
})

輸出

Welcome to Prisma Day 2020
1
2
3
4
5
6
How to Prisma!
1
2
3
4
5
6

效能與適當的用例

中介層會為每個查詢執行,這表示過度使用可能會對效能產生負面影響。為了避免增加效能開銷

  • 在您的中介層中儘早檢查 params.modelparams.action 屬性,以避免不必要地執行邏輯

    prisma.$use(async (params, next) => {
    if (params.model == 'Post' && params.action == 'delete') {
    // Logic only runs for delete action and Post model
    }
    return next(params)
    })
  • 考量中介層是否是您情境的適當解決方案。例如

    • 如果您需要填充欄位,您可以使用 @default 屬性嗎?
    • 如果您需要設定 DateTime 欄位的值,您可以使用 now() 函數或 @updatedAt 屬性嗎?
    • 如果您需要執行更複雜的驗證,您可以在資料庫本身中使用 CHECK 約束嗎?