跳到主要内容

中间件

警告

已废弃:中间件在版本 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.model` 和 `params.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` 约束吗?
© . All rights reserved.