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

我有一种情况,使用我们的 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

}


在我看来,这会添加不必要的额外代码和逻辑来抽象问题,但是我没有看到任何其他优雅的解决方案。


老实说,我不喜欢这两种方法,我想知道你们是否遇到了同样的问题以及如何解决它。


素胚勾勒不出你
浏览 414回答 3
3回答

千巷猫影

您带来的第一个解决方案是一个很好的解决方案。一些众所周知的框架用于实现类似的逻辑。例如,最新的 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)  endend由于第二个版本只允许允许的值,它会阻止用户更改有效负载并发送包含新密码值的 JSON:{ name: "acme", age: 25, password: 'account-hacked' }

当年话下

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

holdtom

这可以通过将 JSON 主体解码为map[string]json.RawMessage第一个来解决。该json.RawMessage类型对于延迟实际解码很有用。之后,可以在map[string]json.RawMessage地图上应用白名单,忽略不需要的属性,只解码json.RawMessage我们想要保留的属性。可以使用reflect包自动将列入白名单的 JSON 主体解码为结构体的过程;可以在此处找到示例实现。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go