为了账号安全,请及时绑定邮箱和手机立即绑定

使用 Golang 从 PUT/PATCH 忽略 JSON 有效负载中不需要的字段的最佳方法是什么?

使用 Golang 从 PUT/PATCH 忽略 JSON 有效负载中不需要的字段的最佳方法是什么?

Go
素胚勾勒不出你 2021-09-10 18:02:59
我有一种情况,使用我们的 API 的人需要对我的资源进行部分更新。我知道 HTTP 明确指定这是一个 PATCH 操作,即使我们这边的人习惯于为此发送 PUT 请求,这就是遗留代码的构建方式。作为示例,想象一下简单的以下结构:type Person struct {    Name string    Age int    Address string}在 POST 请求中,我将提供包含所有三个值(名称、年龄、地址)的有效负载,并在我的 Golang 后端相应地验证它们。简单的。但是,对于 PUT/PATCH 请求,我们知道,例如,aname永远不会改变。但是如果我想更改age,那么我只需发送一个包含新的 JSON 有效负载age:PUT /person/1 {age:30}现在我的真正问题是:防止name我们的 API 的使用者发送包含该name字段的 JSON 有效负载时有意或无意地使用/更新的最佳实践是什么?例子:PUT /person/1 {name:"New Name", age:35} 我想到的但实际上并不喜欢它们的可能解决方案是:在我的validator方法中,我要么强行删除不需要的字段,要么name回复一条错误消息,说这name是不允许的。创建一个 DTO 对象/结构,它几乎是我的Person结构的扩展,然后将我的 JSON 有效负载解组到其中,例如type PersonPut struct {    Age int    Address string}在我看来,这会添加不必要的额外代码和逻辑来抽象问题,但是我没有看到任何其他优雅的解决方案。老实说,我不喜欢这两种方法,我想知道你们是否遇到了同样的问题以及如何解决它。
查看完整描述

3 回答

?
千巷猫影

TA贡献1829条经验 获得超7个赞

您带来的第一个解决方案是一个很好的解决方案。一些众所周知的框架用于实现类似的逻辑。


例如,最新的 Rails 版本带有一个内置的解决方案,以防止用户在请求中添加额外的数据,从而导致服务器更新数据库中的错误字段。它是一种由ActionController::Parameters类实现的白名单。


假设我们有一个如下所示的控制器类。出于本说明的目的,它包含两个update操作。但是你不会在真正的代码中看到它。


class PeopleController < ActionController::Base


  # 1st version - Unsafe, it will rise an exception. Don't do it

  def update

    person = current_account.people.find(params[:id])

    person.update!(params[:person])

    redirect_to person

  end


  # 2nd version - Updates only permitted parameters

  def update

    person = current_account.people.find(params[:id])

    person.update!(person_params) # call to person_params method

    redirect_to person

  end



  private


  def person_params

    params.require(:person).permit(:name, :age)

  end


end

由于第二个版本只允许允许的值,它会阻止用户更改有效负载并发送包含新密码值的 JSON:


{ name: "acme", age: 25, password: 'account-hacked' }


查看完整回答
反对 回复 2021-09-10
?
当年话下

TA贡献1890条经验 获得超9个赞

如果无法写入名称,则无法为任何更新请求提供该名称。如果名称存在,我会拒绝该请求。如果我想要更宽容,我可能会考虑仅在 name 与当前 name 不同时拒绝请求。

我不会默默地忽略与当前名称不同的名称。


查看完整回答
反对 回复 2021-09-10
?
holdtom

TA贡献1805条经验 获得超10个赞

这可以通过将 JSON 主体解码为map[string]json.RawMessage第一个来解决。该json.RawMessage类型对于延迟实际解码很有用。之后,可以在map[string]json.RawMessage地图上应用白名单,忽略不需要的属性,只解码json.RawMessage我们想要保留的属性。

可以使用reflect包自动将列入白名单的 JSON 主体解码为结构体的过程;可以在此处找到示例实现。


查看完整回答
反对 回复 2021-09-10
  • 3 回答
  • 0 关注
  • 413 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信