2 回答

TA貢獻1799條經驗 獲得超9個贊
Deepankar 概述了一種解決方案,但我確實看到了將所有響應數(shù)據保存在模式定義的響應結構中的吸引力。protoc-gen-go如果生成的 setter 與 getter 一起使用,這肯定會更簡單!
我找不到將舊響應中的標頭/尾部復制到新響應中的方法。(我認為此時它們還沒有真正確定,但我不確定。)
你不需要這樣做。在您的示例中,res.Any()返回指向 protobuf 消息的指針 - 您可以就地修改它。您的類型開關可能如下所示:
switch resMsg := res.Any().(type) {
case *livev1.StartResponse:
resMsg.DeviceOffset = durationpb.New(deviceTimeOffset)
case *livev1.StatusResponse:
resMsg.DeviceOffset = durationpb.New(deviceTimeOffset)
}
return res, err
使用類型斷言需要我為每種類型一遍又一遍地重復幾乎相同的代碼塊。
不幸的是,你最好的選擇可能是反思。您可以在標準 Go 反射或 protobuf 反射之間進行選擇——兩者都可以。使用 protobuf 反射,這樣的事情應該可以解決問題:
res, err := next(ctx, req)
if err != nil {
return nil, err
}
msg, ok := res.Any().(proto.Message)
if !ok {
return res, nil
}
// Keep your logic to calculate offset!
var deviceTimeOffset time.Duration
// You could make this a global.
durationName := (*durationpb.Duration)(nil).ProtoReflect().Descriptor().FullName()
refMsg := msg.ProtoReflect()
offsetFD := refMsg.Descriptor().Fields().ByName("DeviceOffset")
if offsetFD != nil &&
offsetFD.Message() != nil &&
offsetFD.Message().FullName() == durationName {
refOffset := durationpb.New(deviceTimeOffset).ProtoReflect()
refMsg.Set(
offsetFD,
protoreflect.ValueOf(refOffset),
)
}
return res, nil
這取決于您是否認為這比重復類型切換更好或更差——它要復雜得多,但它確實讓事情變得更干燥。

TA貢獻1936條經驗 獲得超7個贊
您是否有可能使用標題而不是正文。如果客戶端可以NowOnDevice通過請求標頭發(fā)送,那么您可以改為在響應標頭中發(fā)回響應。Unix 時間戳可能是最好的方法。
func MakeDeviceTimeInterceptor() connect.UnaryInterceptorFunc {
return func(next connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
now := time.Now().UTC()
ctxa := context.WithValue(ctx, CurrentTimestampKey{}, now)
var deviceTimeOffset time.Duration
// Check the header message `now-on-device` field, instead of body
reqWithNow := req.Header().Get("now-on-device")
if reqWithNow != "" {
val, err := strconv.Atoi(reqWithNow)
if err != nil {
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("invalid timestamp"))
}
deviceTime := time.Unix(int64(val), 0)
deviceTimeOffset = now.Sub(deviceTime)
ctxa = context.WithValue(ctxa, DeviceTimeDiffKey{}, deviceTimeOffset)
}
res, err := next(ctxa, req)
// Set to response header if value is set
if deviceTimeOffset != 0 {
res.Header().Set("device-time-offset", fmt.Sprintf("%d", deviceTimeOffset))
}
return res, err
}
}
}
然后你有回應:
curl -v \
--header "Content-Type: application/json" --header "now-on-device: 1656442814" \
--data '{"name": "Jane"}' \
http://localhost:8080/greet.v1.GreetService/Greet
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /greet.v1.GreetService/Greet HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.79.1
> Accept: */*
> Content-Type: application/json
> now-on-device: 1656442814
> Content-Length: 16
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Accept-Encoding: gzip
< Content-Type: application/json
< Device-Time-Offset: 7259524766000
< Greet-Version: v1
< Date: Tue, 28 Jun 2022 21:01:13 GMT
< Content-Length: 27
<
* Connection #0 to host localhost left intact
{"greeting":"Hello, Jane!"}
- 2 回答
- 0 關注
- 142 瀏覽
添加回答
舉報