我看不出 put 和 patch 方法之间的区别

问题描述

我只想喜欢一个引文,或者不喜欢我已经喜欢的引文。所以首先我找到报价,然后我检查我是否已经喜欢这个报价,如果不是那么我喜欢,否则我不喜欢。

我有一个像下面这样的路由器

router.put('/:quoteId',isAuth,quotesController.likeQuote);

likeQuote 方法如下

module.exports.likeQuote = (req,res,next) => {
  const quoteId = req.params.quoteId;
  const userId = req.userId;
  Quote.findById(quoteId)
    .then((quote) => {
      if (quote.likes.indexOf(userId) == -1) {
        quote.likes.push(userId);
      } else {
        quote.likes.pull(userId);
      }
      return quote.save();
    })
    .then((updatedQuote) => {
      res.status(201).json({ message: 'You liked the post!' });
    })
    .catch((err) => {
      err.statusCode = 500;
      next(err);
    });

但我的问题是,我只想知道 PUTPATCH 是如何工作的?我认为我们应该发送 PUT 中的所有字段,而不是 PATCH 方法中的所有字段,但在我的情况下,我什至不发送任何字段,并且两者都可以正常工作。这是怎么发生的?

解决方法

实际的 REST API 方法(PUTPATCH、...)没有任何限制。您选择编写的逻辑定义了这一点。现在您正在询问“最佳实践”,每当您询问时,您都会得到许多不同的答案。我会解释我的观点。

PUT,所以 PUT 的本质是完全替换现有对象,这就是为什么人们告诉你发送整个对象,因为当你使用 PUT 时,预期的是完全交换。

PATCHPATCH的本质是更新现有资源。这就是您要查找的内容,在这种情况下,您只需发送更新所需的必填字段。

现在,如果您将 PUT 写为更新而不是完整的交换是错误的吗?我认为它不是。只要您在整个应用中保持一致的逻辑,您就可以构建适合您需求的“最佳实践”。

现在您确实将此问题标记为与 Mongo 相关,因此我想向您介绍 piplined updates(适用于 Mongo v4.2+)的概念,您可以在其中一次更新执行您的逻辑.

Mongo Playground

,

我只想知道 PUT 和 PATCH 是如何工作的?

要理解的一个重要区别是,我们没有关于 PUT 和 PATCH 工作方式的标准;这是一个实现细节,故意隐藏在“统一接口”后面。

我们所拥有的是标准化的语义,即关于 PUT 和 PATCH 含义的协议。

(由于人们不熟悉该标准,这进一步复杂化,因此对含义的误解很常见。)

如果请求处理程序的实现与请求的语义不匹配,那没关系……但如果结果出现代价高昂的错误,那就是实现的错。


PUT 和 PATCH 都是方法令牌,表明我们正在尝试修改由 target-uri 标识的资源。特别是,当我们试图使服务器对资源的表示与客户端上的表示相匹配时,我们会使用这些方法标记。

例如,想象一下编辑网页。我们GET /home.html,更改副本中的 TITLE 元素,并且我们希望将更改保存到服务器。我们如何在 HTTP 中做到这一点?

一个答案是我们将 home.html 的副本(带有我们的更改)发送回服务器,以便服务器可以保存它。就是这样。

另一个答案是我们比较我们的副本和服务器的副本,然后向服务器发送一个补丁文档,描述服务器应该对其副本进行的更改。那是补丁。


router.put('/:quoteId',isAuth,quotesController.likeQuote);

此调用正在配置框架,以便将具有 PUT 方法令牌和与“/:quoteId”匹配的目标 uri 的请求委托给 likeQuote 方法。

在这个级别,框架假设您知道自己在做什么 - 没有尝试验证“likeQuote”是否实现了 PUT 语义。为了确保实现和请求语义匹配,您需要做一些工作(检查代码、测试等)。

在我的情况下,我什至不发送任何字段,两者都可以正常工作。

正确 - 因为框架假设您知道自己在做什么,并且您当前的实现不会尝试访问或解释 HTTP 请求的正文。

注意:这是一个很大的暗示,请求处理程序实际上没有实现 PUT/PATCH 语义(如果服务器不查看客户端提供的信息,它怎么可能使它的引用副本看起来像客户端的)?

It is okay to use POST;假设您的实现是正确的,您不应该使用具有远程创作语义的方法,因为这不是您正在做的。附加到 POST 路由的相同实现将很好

事实上,事情已经坏了 - 请求语义和处理程序实现之间存在不匹配。在受控条件下,您可能会侥幸逃脱。您完全有可能只在受控条件下调用此代码。