第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在 connect-go 攔截器中修改 responsebody

在 connect-go 攔截器中修改 responsebody

Go
慕碼人2483693 2022-12-26 16:45:26
我正在使用 Buf 的connect-go庫來實現(xiàn) gRPC 服務器。許多 gRPC 調用對時間敏感,因此它們包含一個字段,客戶端使用該字段發(fā)送其當前時間戳。服務器將客戶端時間戳與本地時間戳進行比較,并返回它們之間的差異。這是.proto定義中的示例:service EventService {    // Start performing a task    rpc Start (StartRequest) returns (StartResponse);}message StartRequest {    int64 location_id = 1;    int64 task_id = 2;    Location user_latlng = 3;    google.protobuf.Timestamp now_on_device = 4;}message StartResponse {    TaskPerformanceInfo info = 1;    google.protobuf.Duration device_offset = 2;}因為我已經為幾個 RPC 方法實現(xiàn)了這個,所以我想看看我是否可以使用攔截器來處理它,所以我不需要確保它在所有單獨的 RPC 方法實現(xiàn)中都被處理。由于protoc-gen-go編譯器為字段定義 getter 的方式,檢查請求消息是否包含now_on_device字段很容易通過定義接口和使用類型斷言來完成:type hasNowOnDevice interface {    GetNowOnDevice() *timestamppb.Timestamp}if reqWithNow, ok := req.Any().(hasNowOnDevice); ok {   // ...}這使得大部分攔截器非常容易編寫:func MakeDeviceTimeInterceptor() func(connect.UnaryFunc) connect.UnaryFunc {    return connect.UnaryInterceptorFunc(        func(next connect.UnaryFunc) connect.UnaryFunc {            return connect.UnaryFunc(func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {                now := time.Now().UTC()                ctxa := context.WithValue(ctx, CurrentTimestampKey{}, now)                var deviceTimeOffset time.Duration                // If the protobuf message has a `NowOnDevice` field, use it                // to get the difference betweent the device time and server time.                if reqWithNow, ok := req.Any().(hasNowOnDevice); ok {                    deviceTime := reqWithNow.GetNowOnDevice().AsTime()                    deviceTimeOffset = now.Sub(deviceTime)                    ctxa = context.WithValue(ctxa, DeviceTimeDiffKey{}, deviceTimeOffset)                }                res, err := next(ctxa, req)                // TODO: How do I modify the response here?                return res, err            })        },    )}我遇到的問題(如上面評論中所述)是如何修改響應。
查看完整描述

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

這取決于您是否認為這比重復類型切換更好或更差——它要復雜得多,但它確實讓事情變得更干燥。


查看完整回答
反對 回復 2022-12-26
?
LEATH

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!"}


查看完整回答
反對 回復 2022-12-26
  • 2 回答
  • 0 關注
  • 142 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號