所以我将kratos框架与Go结合使用,我的API定义是:

rpc UpdateMeeting (UpdateMeetingRequest) returns (UpdateMeetingReply) {
    option (google.api.http) = {
      patch: "/v1/meetings/{meeting_id}"
      body: "*"
    };
  };

和相应的KRATOS生成的函数

func _Meeting_UpdateMeeting_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
    in := new(UpdateMeetingRequest)
    if err := dec(in); err != nil {
        return nil, err
    }
    if interceptor == nil {
        return srv.(MeetingServer).UpdateMeeting(ctx, in)
    }
    info := &grpc.UnaryServerInfo{
        Server:     srv,
        FullMethod: Meeting_UpdateMeeting_FullMethodName,
    }
    handler := func(ctx context.Context, req interface{}) (interface{}, error) {
        return srv.(MeetingServer).UpdateMeeting(ctx, req.(*UpdateMeetingRequest))
    }
    return interceptor(ctx, in, info, handler)
}

现在,如果我将以下内容作为消息请求,则解组没有任何问题,并且请求实际上落在从Kratos生成的方法调用的UpdateMeeting方法上.

message UpdateMeetingRequest {

  string  meeting_id = 1;

  string updated_by = 2;

  MeetingMeta meeting_meta = 3;
  // more fields left out
}

message MeetingMeta {
  string meeting_link = 1;
  // more fields left out
}

但是,当我添加FieldMASK时,我实际上需要判断哪个字段存在,哪个不存在,我得到这个错误-

message UpdateMeetingRequest {

  string  meeting_id = 1;

  string updated_by = 2;

  MeetingMeta meeting_meta = 3;

  google.protobuf.FieldMask update_mask = 4;
}


Error
{
    "code": 400,
    "reason": "CODEC",
    "message": "body unmarshal proto: (line 5:18): google.protobuf.FieldMask.paths contains invalid path: \"meeting_meta\"",
    "metadata": {}
}

有效载荷

{
  "meeting_meta": {
      "meeting_link": "ac"
  },
  "update_mask": "meeting_meta"
}

对于try 的更新掩码:MeetingMeta.Meetinglink、MeetingMeta、Meetinglink这三个都有相同或类似的错误.

编辑: 因此,使用答案中提到的方法,我能够通过更改UPDATE_MASK来使其工作.MeetingMeta->MeetingMeta.

但也会遇到同样的问题,即如果有效负载中有两个字段的名称中有‘_’,则会出现"包含无效路径"的情况.示例:

{
  
  "updated_by": "dsjhvg",
  "meeting_meta": {
      "meeting_link": "ac"
  },
  "update_mask": "updatedBy, meetingMeta"
}

单独来看,这两个字段都被很好地解组了.总而言之,我在UPDATE_MASK中的第二个路径上遇到了错误.对于这个有效载荷,它是meeting_meta,如果我重新排列它们,那么它是updated_by.

推荐答案

应将有效载荷修改为:

{
  "meeting_meta": {
      "meeting_link": "ac"
  },
  "update_mask": "meetingMeta"
}

(将"update_mask": "meeting_meta"替换为"update_mask": "meetingMeta")

根据JSON Encoding of Field Masks,每个路径中的字段名称将与lower-camel命名约定相互转换.

下面从google.golang.org/protobuf/encoding/protojson包复制的源代码显示了如何验证字段名(参见第20行,不允许在字段名中使用_):

 1  func (d decoder) unmarshalFieldMask(m protoreflect.Message) error {
 2      tok, err := d.Read()
 3      if err != nil {
 4          return err
 5      }
 6      if tok.Kind() != json.String {
 7          return d.unexpectedTokenError(tok)
 8      }
 9      str := strings.TrimSpace(tok.ParsedString())
10      if str == "" {
11          return nil
12      }
13      paths := strings.Split(str, ",")
14  
15      fd := m.Descriptor().Fields().ByNumber(genid.FieldMask_Paths_field_number)
16      list := m.Mutable(fd).List()
17  
18      for _, s0 := range paths {
19          s := strs.JSONSnakeCase(s0)
20          if strings.Contains(s0, "_") || !protoreflect.FullName(s).IsValid() {
21              return d.newError(tok.Pos(), "%v contains invalid path: %q", genid.FieldMask_Paths_field_fullname, s0)
22          }
23          list.Append(protoreflect.ValueOfString(s))
24      }
25      return nil
26  }

第二个问题的答案.

如果您仔细查看错误消息,您将看到类似以下内容:

google.protobuf.FieldMask.paths contains invalid path: " meetingMeta"

您会看到报告的无效路径是" meetingMeta".注意前面的空格.这意味着该包不会为您修剪路径.因此,您不应该在路径之间添加空格.有效负载应为:

{
  
  "updated_by": "dsjhvg",
  "meeting_meta": {
      "meeting_link": "ac"
  },
  "update_mask": "updatedBy,meetingMeta"
}

Go相关问答推荐

如何在使用中介资源时处理函数中的`defer`

如何将文件从AWS S3存储桶复制到Azure BLOB存储

Go源在Goland(IDEA)中以灰色显示.什么意思?我怎么才能让它恢复正常?

Go 中的 protobuf FieldMask 解组

如何为ANTLR4目标Go调试监听器

从单词中删除特殊字符

在本地 go 应用程序上获取秘密的正确策略

整理时转换值

golang 中的可变参数函数

Go:从 ssl 证书中获取 'subject/unstructeredName' 的值

在我的情况下,如何以正确的方式测试方法?

Golang:隐式 struct 匹配

Go:等待多个通道的性能损失

httprouterhttp.HandlerFunc() 是如何工作的?

如何排除溢出矩阵的坐标

GORM GIN 更新查询导致 500 内部服务器错误

(如何)我可以基于接口抽象地实现Stringer吗?

comparable和any有什么区别?

空接口与泛型接口有何不同?

Go 语言的select语句