micro / go-micro

A Go microservices framework
https://go-micro.dev
Apache License 2.0
21.82k stars 2.35k forks source link

timestamppb.timestamp cause "json: cannot unmarshal object into Go value of type string" after upgrade v4.6 #2596

Closed gzhhong closed 2 months ago

gzhhong commented 1 year ago

Describe the bug

  1. I use golang and upgrade go micro from v4.5 to v4.6
  2. I expected that all of my integration test should pass
  3. What happens instead? My logger print errors below: {\"id\":\"go.micro.client.codec\",\"code\":500,\"detail\":\"json: cannot unmarshal object into Go value of type string\",\"status\":\"Internal Server Error\"} In general it is said go.micro.client.codec has error json: cannot unmarshal object into Go value of type string.

How to reproduce the bug

My message structure in proto file

message Meeting {
    // @inject_tag: json:"start" validate:"required"
    google.protobuf.Timestamp start = 1;
}

The golang structure created by protoc

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

    // @inject_tag: json:"start" validate:"required"
    Start *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=start,proto3" json:"start" validate:"required"`
}

When I assign value to meeting.Start, the code like:

    meeting.Start = timestamp.New(model.Start) // timestamp imported from "google.golang.org/protobuf/types/known/timestamppb"

There is no such value if I continue using go micro v4.5. I am using libprotoc 3.21.6 and protoc-gen-go v1.27.1

Go Version output:

go version go1.17.13 darwin/amd64

The go env output:

GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/zhihong/Library/Caches/go-build"
GOENV="/Users/zhihong/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/zhihong/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/zhihong/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.17.13"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/r7/f018pp653m3_fw0xv9jx_tgh0000gn/T/go-build2635807831=/tmp/go-build -gno-record-gcc-switches -fno-common"

Any suggestions welcomed, thanks,

James

Davincible commented 1 year ago

Thanks for reporting this! We should definitely look into this. Are there any tests, non specific to your system that you could provide that we could test with?

jochumdev commented 1 year ago

Hey @gzhhong / James,

just switch the clients DefaultContentType to "application/proto". I would as well switch server AND client to gRPC.

Let me know when you need help.

Kind Regards, René

gzhhong commented 1 year ago

@Davincible , Hello David, I upload a test project at https://github.com/gzhhong/test-grpc. I hope I made it clear in the readme and the code. @jochumdev , Hello Rene, could you please help to correct my sample code if possible?

Thanks both of you.

James

Davincible commented 1 year ago

@gzhhong hmm the request is never actually reaching the server on the second one.. interesting. This is gonna take some debugging.

Thanks for the example!

tttao7 commented 1 year ago

Hey @gzhhong / James,

just switch the clients DefaultContentType to "application/proto". I would as well switch server AND client to gRPC.

Let me know when you need help.

Kind Regards, René

Hello @jochumdev / René ,

How to set DefaultContentType to "application/proto", can you give an example, thank you very much.

It's not okay to write like this

client.DefaultContentType = "application/protobuf"

Then I wrote it like this, and it always feels weird.

client.DefaultContentType = "application/protobuf"
client.DefaultClient = client.NewClient(client.ContentType(client.DefaultContentType))

Thank you !

jochumdev commented 1 year ago

Hi @tttao7 ,

I recommend something like (untested):

package main

import (
    "go-micro.dev/v4"
    grpcClient "github.com/go-micro/plugins/v4/client/grpc"
    grpcServer "github.com/go-micro/plugins/v4/server/grpc"
)

func main() {
    service := micro.NewService(
        micro.Name("greeter"),
        micro.Server(grpcServer.NewServer()),
        micro.Client(grpcClient.NewClient(client.ContentType("application/protobuf"))),
    )
}

Switching Server & Client to grpc will boost your application a lot AND it will work with protobuf.