什么时候应该使用Zod?

本文探讨了在不同情境下如何利用Zod进行输入验证,包括不信任的公共API请求、部分信任的第三方服务以及完全可控的内部数据。作者强调了Zod在确保数据安全和易于调试中的重要性,同时也讨论了在特定情况下跳过验证的考虑因素,如性能和版本控制问题。
摘要由CSDN通过智能技术生成

图片


作为一个工程师,你会构建一些东西。
你正在构建的东西可能会有输入——数据被注入的点。


假设你正在构建一个名为 mycli 的CLI:

mycli run <something>

这里,<something> 是输入。它告诉程序该做什么。它在运行时是完全未知的,它甚至可能不是存在的。


如果你正在构建一个面向公众的API,你的输入可能会暴露在web上的公共端口上:

GET https://somesite.com/api/user/:idPOST https://somesite.com/api/user/:id


我想到了几个可能的输入:
 

  • 路径中的 :id 参数

  • 您使用了哪个REST方法( GET 或 POST )

  • 请求的标头

  • 添加到请求中的搜索参数: ?hello=world

  • 请求体(for  POST )


所有这些在运行时都是未知的,因为如果这些API暴露给外界,任何人都可以ping通它们。如果它们没有得到验证,许多甚至可能成为攻击的载体。


当你不信任输入时
 

在这些情况下,你都不相信进入应用程序的数据。对于这些情况,你应该使用Zod。
 

对于脚本,您可以解析 process.argv :

import {z} from 'zod'
// Make a schema for the argumentsconst ArgSchema = z.tuple([z.any(), z.any(), z.string()])
// Use it to parse process.argvconst [, , name] = ArgSchema.parse(process.argv)
// Log it to the console safely!console.log(name)

process.argv通常包含两个无用的参数,然后是您想要提取的动态参数。对于更复杂的情况,您可能希望使用 commander — 但是对于简单的脚本,这非常有效。

这里使用Zod的好处是 name 被推断为 string ,而不需要任何其他工作。


对于公共API,您可以创建Zod模式来确保请求体和头是正确的。
​​​​​​

import {z} from 'zod'import {Request, Response} from 'express'
const CreateUserSchema = z.object({  body: z.object({    // Ensures that the email exists, and is an email    email: z.string().email(),  }),  headers: z.object({    // Ensures that the authorization header is present    authorization: z.string(),  }),})
const handleCreateUser = (req: Request, res: Response) => {  // Parse the request  const result = CreateUserSchema.safeParse(req)
  // If something was missing, send back an error  if (!result.success) {    res.status(400).send(result.error)    return  }
  const {email} = result.data.body
  // Create the user}

这里使用 .safeParse 是为了不抛出错误,而是返回 400 并将错误传递回去。Zod抛出了非常好的、可读的错误,因此我们可以确保用户知道哪里出了问题。


多亏了Zod,你可以确保应用程序中的未知输入是经过验证和安全的。如果我正在构建一个带有未知输入的应用程序,我会立即添加Zod。


更多未知输入的例子:
 

  • 表单——登录表单、CRUD表单……这些都是Zod的伟大用例

  • Websocket连接

  • localStorage  -用户可以操作它,否则它可能已经过期。


当你“有点”相信输入的时候
 

对于应用程序中不可信的输入,Zod的用例是显而易见的。但还有其他类型的输入是你“有点”信任的。


我想到的例子是第三方服务。如果你的应用依赖于调用一个你无法控制的第三方API,你应该用Zod验证这个API吗?


如果API改变了形状,可能会在应用程序中造成细微的错误。作为一名工程师,我已经经历过很多次了:在意识到API返回了一些我没有预料到的东西之前,假设我的代码是错误的。


用Zod验证数据仍然会在你的应用程序中导致一个错误——但是这个错误会在数据进入你的应用程序时被抛出。这使得它更容易调试和修复。


在这种情况下,为什么不验证呢? 如果考虑到包的大小,Zod是12kb的压缩包,这对一些应用来说有点大了。验证也不可避免地比不验证稍微慢一些。因此,如果关注关键路径性能,您可能希望跳过Zod。


然而,在我职业生涯中构建的大多数应用程序中,健壮性是关键问题。“不可能的数据”——或者你不期望的数据——可能是我整个开发生涯中最常见的bug原因。所以我会验证任何不可信的输入。


一些更“有点”值得信赖的输入:
 

  • 公共API,比如GitHub和YouTube

  • API由组织中的其他团队控制(这是有争议的,但根据文化,我会考虑将Zod作为一种选择)


当你能控制输入的时候
 

我们来看最后一种情况。想象一下,你正在构建一个全栈应用程序,使用流行的框架,如Remix, Next.js, SvelteKit或next。


您希望从前端加载一些数据。您ping一个API端点(由于它是面向公众的,因此可能已经通过Zod进行了验证)。你会得到一些数据。您是否应该在前端使用Zod验证该数据?


这是一个棘手的问题。我们完全控制API端点——我们负责部署到它,并且它与前端同步部署。然而,仍然有可能发生以下顺序:
 

  1. 用户在我们的页面上启动浏览器会话(不刷新)。假设这是一个金融应用,通过ping API,图表每10秒刷新一次。

  2. 当他们浏览时,我们重新部署我们的应用程序,对后端进行了一些突破性的更改。

  3. 用户仍然没有刷新页面,但现在他们ping的后端已经过期了。书页开始破裂。


这种前端和后端之间的“版本漂移”比你想象的更常见,特别是考虑到一些团队部署的频率。如果我们将Zod放在前端,我们就能够在任何版本漂移发生时立即出错,并提示用户刷新页面。


然而,在这些情况下,我通常选择不使用Zod。有了版本漂移,应用程序通常只是一次浏览器刷新,就能获得更好的体验。由于没有任何安全敏感的内容暴露给前端代码,因此漏洞的爆炸半径相对较小。


这是有争议的,尽管每当一个版本漂移发生时,你可能想要检查所有的数据进入你的应用程序的错误。


总结
 

当你的应用有你不信任的输入时,使用Zod。

当你的应用有你信任但无法控制的输入时,用Zod验证它们。

当你的应用程序有你信任和控制的输入时,我通常不会与Zod验证它们。

 
​​​​​​​欢迎关注公众号:文本魔术,了解更多

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值