我正在使用gRPC构建API,并且在服务器端,我希望在客户端断开连接时收到通知,识别它并基于此执行一些任务。
到目前为止,我已经能够使用grpc.StatsHandler
方法HandleConn
检测到客户端断开连接。我尝试使用上下文传递值,但是无法从服务器端访问它们。
客户端:
conn, err := grpc.DialContext(
context.WithValue(context.Background(), "user_id", 1234),
address,
grpc.WithInsecure(),
)
服务器端:
// Build stats handler
type serverStats struct {}
func (h *serverStats) TagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context {
return ctx
}
func (h *serverStats) HandleRPC(ctx context.Context, s stats.RPCStats) {}
func (h *serverStats) TagConn(ctx context.Context, info *stats.ConnTagInfo) context.Context {
return context.TODO()
}
func (h *serverStats) HandleConn(ctx context.Context, s stats.ConnStats) {
fmt.Println(ctx.Value("user_id")) // Returns nil, can't access the value
switch s.(type) {
case *stats.ConnEnd:
fmt.Println("client disconnected")
break
}
}
// Build server
s := grpc.NewServer(grpc.StatsHandler(&serverStats{}))
我想访问服务器端从客户端传递的值。正确的方法是什么,还是有其他方法可以识别断开连接的客户端?
答案 0 :(得分:1)
我认为您在拨号时可能不会传递该值,但是您可以标记连接,然后所有下一个客户端请求在其上下文中将具有相同的值:
在您的serverStats实现中:
code
在您的服务实施中
...
if (preObj != null) {
//createCode();
code = createCode();
}
...
在其他方法中:
export function MakeAuthstateObservable(
auth: firebase.auth.Auth
): Observable<firebase.User> {
const authState = Observable.create((observer: Observer<firebase.User>) => {
auth.onAuthStateChanged(
(user?: firebase.User) => observer.next(user),
(error: firebase.auth.Error) => observer.error(error),
() => observer.complete()
);
});
return authState;
}
func (h *serverStats) TagConn(ctx context.Context, info *stats.ConnTagInfo) context.Context {
return context.WithValue(ctx, "user_counter", userCounter++)
}
如果您在拨号步骤中找到了一种传递值的方法,请告诉我。
答案 1 :(得分:0)
我尝试使用上下文传递值,但是无法从服务器端访问它们。
您需要将元数据字段显式设置为客户端上下文:
ctx := context.Background()
ctx = metadata.AppendToOutgoingContext(ctx, "user_id", "1234")
conn, err := grpc.DialContext(cxt, address)
在服务器端,您可以像这样检索它们:
md, ok := metadata.FromIncomingContext(ctx)
正确的方法是什么,或者还有其他方法来识别断开连接的客户端吗?
这实际上取决于您的用例。我认为GRPC Stats API对于某些简单任务(例如,计算延迟或汇总网络统计信息)非常有用,但是当客户端离开时某些业务逻辑应该工作时,它并不是很有用。我建议为此直接在GRPC处理程序中使用defer
调用。另一种选择是实现自定义GRPC拦截器。