【问题标题】:json unmarshall not working on golang protojson unmarshal 不适用于 golang proto
【发布时间】:2023-02-05 11:34:28
【问题描述】:

我收到了一个 http 请求的响应

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImZCRXFDSnFER21hMUxLZUtoZUVxcSJ9.eyJpc3MiOiJodHRwczovL2Rldi0xY3p5M3Vpa21pNjJ0dWN4LnVzLmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHw0OTAiLCJhdWQiOiJhdXRoLXNlcnZpY2Ui...",
  "scope": "read:sample",
  "expires_in": 86400,
  "token_type": "Bearer"
}

我想将此响应解组为 golang 中的以下原型:

message Token {
  // jwt access token
  string access_token = 1;
  // scope of the token
  string scope = 2;
  // expiration time
  int32 expires_in = 3;
  // token type
  string token_type = 4;
}

此外,这是 generated go struct:

type Token struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    // jwt access token
    AccessToken string `protobuf:"bytes,1,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"`
    // scope of the token
    Scope string `protobuf:"bytes,2,opt,name=scope,proto3" json:"scope,omitempty"`
    // expiration time
    ExpiresIn int32 `protobuf:"varint,3,opt,name=expires_in,json=expiresIn,proto3" json:"expires_in,omitempty"`
    // token type
    TokenType string `protobuf:"bytes,4,opt,name=token_type,json=tokenType,proto3" json:"token_type,omitempty"`
}

我从json/encoding包中尝试了json.NewDecoder(resp.Body).Decode(&token)。 也试过这个:

    token := new(v1_stubs.Token)
    if err := jsonpb.Unmarshal(resp.Body, token); err != nil {
        log.Context(ctx).Errorf("failed to decode `get token` response")
        return nil, err
    }

v1_stubs.Token 生成的是上述原型的结构。

问题是:当我将令牌转换为 json 时,我得到 as 输出:

{
    "token": {
        "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImZCRXFDSnFER21hMUxLZUtoZUVxcSJ9.eyJpc3MiOiJodHRwczovL2Rldi0xY3p5M3Vpa21pNjJ0dWN4LnV...",
        "scope": "read:sample",
        "expires_in": "\"\u0006Bearer",
        "token_type": ""
    }
}

看起来 expires_in 字段中缺少一些数据,token_type 合并到 expires_in 中。

【问题讨论】:

  • 您可以分享 v1_stubs.Token 的生成定义吗?
  • 添加了生成的 def。谢谢

标签: go protocol-buffers grpc


【解决方案1】:

这是一个从头开始的例子。也许您可以重现它并查看您的本地设置与此设置有何不同? (jsonpb 包的官方文档说它已被弃用,取而代之的是 "google.golang.org/protobuf/encoding/protojson",因此我提供了两个代码示例,它们似乎都能按预期工作。)

// ex.proto
syntax = "proto3";

message Token {
  // jwt access token
  string access_token = 1;
  // scope of the token
  string scope = 2;
  // expiration time
  int32 expires_in = 3;
  // token type
  string token_type = 4;
}

我从下载了全新安装的工具 https://github.com/protocolbuffers/protobuf/releases/tag/v21.12

$ unzip protoc-21.12-linux-x86_64.zip
$ PATH=$(pwd)/bin:$PATH
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
$ protoc -I=./ --go_out=./ --go_opt=Mex.proto=this/ex ex.proto
$ cd this
$ go mod init this

在这个 this 目录中,创建 main_jsonpb.go 文件:

package main

import (
    "fmt"
    "log"

    "this/ex"

    "github.com/golang/protobuf/jsonpb"
)

func main() {
    d := `{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImZCRXFDSnFER21hMUxLZUtoZUVxcSJ9.eyJpc3MiOiJodHRwczovL2Rldi0xY3p5M3Vpa21pNjJ0dWN4LnVzLmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHw0OTAiLCJhdWQiOiJhdXRoLXNlcnZpY2Ui...",
  "scope": "read:sample",
  "expires_in": 86400,
  "token_type": "Bearer"
}`
    var pr ex.Token
    if err := jsonpb.UnmarshalString(d, &pr); err != nil {
        log.Fatalf("failed to unmarshal json: %v", err)
    }
    f := &jsonpb.Marshaler{
        Indent: "  ",
    }
    fmt.Println(f.MarshalToString(&pr))
}

main_protojson.go 文件:

package main

import (
    "fmt"
    "log"

    "this/ex"

    "google.golang.org/protobuf/encoding/protojson"
)

func main() {
    d := []byte(`{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImZCRXFDSnFER21hMUxLZUtoZUVxcSJ9.eyJpc3MiOiJodHRwczovL2Rldi0xY3p5M3Vpa21pNjJ0dWN4LnVzLmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHw0OTAiLCJhdWQiOiJhdXRoLXNlcnZpY2Ui...",
  "scope": "read:sample",
  "expires_in": 86400,
  "token_type": "Bearer"
}`)
    var pr ex.Token
    if err := protojson.Unmarshal(d, &pr); err != nil {
        log.Fatalf("failed to unmarshal json: %v", err)
    }
    fmt.Println(protojson.Format(&pr))
}

然后执行它们:

$ go mod tidy
$ go run main_jsonpb.go
{
  "accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImZCRXFDSnFER21hMUxLZUtoZUVxcSJ9.eyJpc3MiOiJodHRwczovL2Rldi0xY3p5M3Vpa21pNjJ0dWN4LnVzLmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHw0OTAiLCJhdWQiOiJhdXRoLXNlcnZpY2Ui...",
  "scope": "read:sample",
  "expiresIn": 86400,
  "tokenType": "Bearer"
} <nil>
$ go run main_protojson.go
{
  "accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImZCRXFDSnFER21hMUxLZUtoZUVxcSJ9.eyJpc3MiOiJodHRwczovL2Rldi0xY3p5M3Vpa21pNjJ0dWN4LnVzLmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHw0OTAiLCJhdWQiOiJhdXRoLXNlcnZpY2Ui...",
  "scope": "read:sample",
  "expiresIn": 86400,
  "tokenType": "Bearer"
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-13
    • 2015-03-15
    • 2020-08-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多