客户端接收响应超时机制
划线处核心部分
syntax = "proto3";
option go_package = ".;protos";
message User {
string username = 1;
string password = 2;
}
message Msg {
map<string, string> data = 1;
}
message UserRequest {
Msg msg = 1;
}
message UserResponse {
Msg msg = 1;
}
service UserService {
rpc Regist(UserRequest) returns (UserResponse);
rpc Login(UserRequest) returns (UserResponse);
}
package main
import (
"context"
"fmt"
"mini/intercepter/protos"
"net"
"time"
"google.golang.org/grpc"
)
// 介绍 gRPC 的拦截器的简单用法
type UserService struct {
protos.UnimplementedUserServiceServer
}
func (*UserService) Regist(ctx context.Context, req *protos.UserRequest) (*protos.UserResponse, error) {
user := protos.User{Username: req.Msg.GetData()["username"], Password:req.Msg.GetData()["password"] }
_ ,err:= fmt.Println("regist:",user.Username,"-->",user.Password)
if err != nil {
return nil, err
}
return &protos.UserResponse{Msg: req.Msg}, nil
}
func (*UserService) Login(ctx context.Context, req *protos.UserRequest) (*protos.UserResponse, error) {
//-----------------------------------------------------------------------------------------------------
// 测试超时 : 客户端显示 :panic: rpc error: code = DeadlineExceeded desc = context deadline exceeded
time.Sleep(time.Second * 5)
//-----------------------------------------------------------------------------------------------------
user := protos.User{Username: req.Msg.GetData()["username"], Password:req.Msg.GetData()["password"] }
_ ,err:= fmt.Println("login:",user.Username,"-->",user.Password)
if err != nil {
return nil, err
}
return &protos.UserResponse{Msg: req.Msg}, nil
}
func main(){
listen, err := net.Listen("tcp", "127.0.0.1:8080")
if err != nil {
panic(err)
}
g := grpc.NewServer()
//g.RegisterService(&protos.UserService_ServiceDesc, &UserService{})
protos.RegisterUserServiceServer(g, new(UserService))
g.Serve(listen)
}
package main
import (
"context"
"mini/intercepter/protos"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
func main() {
dial, err:= grpc.Dial("127.0.0.1:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
panic(err)
}
client := protos.NewUserServiceClient(dial)
data := map[string]string{
"username" : "admin",
"password" : "12345",
}
//-----------------------------------------------------------------------------------------------------
ctx, cancel := context.WithTimeout(context.TODO(), time.Second*3)
defer cancel()
resp, err := client.Login(ctx, &protos.UserRequest{Msg: &protos.Msg{Data: data}})
//-----------------------------------------------------------------------------------------------------
if err != nil {
panic(err)
}
println(resp.Msg.Data["username"],"--->",resp.Msg.Data["password"])
}
grpc错误处理机制
syntax = "proto3";
option go_package = ".;protos";
message User {
string username = 1;
string password = 2;
}
message Msg {
map<string, string> data = 1;
}
message UserRequest {
Msg msg = 1;
}
message UserResponse {
Msg msg = 1;
}
service UserService {
rpc Regist(UserRequest) returns (UserResponse);
rpc Login(UserRequest) returns (UserResponse);
}
package main
import (
"context"
"fmt"
"mini/intercepter/protos"
"net"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type UserService struct {
protos.UnimplementedUserServiceServer
}
func (*UserService) Regist(ctx context.Context, req *protos.UserRequest) (*protos.UserResponse, error) {
user := protos.User{Username: req.Msg.GetData()["username"], Password:req.Msg.GetData()["password"] }
_ ,err:= fmt.Println("regist:",user.Username,"-->",user.Password)
if err != nil {
return nil, err
}
return &protos.UserResponse{Msg: req.Msg}, nil
}
func (*UserService) Login(ctx context.Context, req *protos.UserRequest) (*protos.UserResponse, error) {
user := protos.User{Username: req.Msg.GetData()["username"], Password:req.Msg.GetData()["password"] }
_ ,err:= fmt.Println("login:",user.Username,"-->",user.Password)
if err != nil {
return nil, err
}
return &protos.UserResponse{Msg: req.Msg}, nil
}
// 服务端的拦截器:
/*
参数:之前的上下文、请求、元数据、处理函数
返回值:响应(元数据)、错误
*/
func Login_Intercepter(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error){
// 其他要求:1. 认证 2. 日志 3. 限流 4. 监控 。。。
fmt.Println("服务端登录拦截器来了~~~")
// 拦截器处理
data, err := Login_Intercepter_Handler(ctx, req)
if err != nil {
return nil, err
}
fmt.Println(data)
// 继续处理请求
resp, err = handler(ctx, req)
// ... 其他处理
return resp, err
}
func Login_Intercepter_Handler(ctx context.Context, req any) (any, error){
data := req.(*protos.UserRequest).Msg.Data
if data["username"] == "admin" && data["password"] == "123456" {
return "通过拦截器", nil
}
// 返回错误, 需要导入两个包
st := status.New(codes.InvalidArgument, "无效的用户名或者密码")
return nil, status.Error(st.Code(), st.Message())
}
func main(){
listen, err := net.Listen("tcp", "127.0.0.1:8080")
if err != nil {
panic(err)
}
opt := grpc.UnaryInterceptor(Login_Intercepter)
g := grpc.NewServer(opt)
//g.RegisterService(&protos.UserService_ServiceDesc, &UserService{})
protos.RegisterUserServiceServer(g, new(UserService))
g.Serve(listen)
}
还是注意看拦截器部分
package main
import (
"context"
"mini/intercepter/protos"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/status"
)
func main() {
dial, err:= grpc.Dial("127.0.0.1:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
panic(err)
}
client := protos.NewUserServiceClient(dial)
data := map[string]string{
"username" : "admin",
"password" : "12345",
}
resp, err := client.Login(context.Background(), &protos.UserRequest{Msg: &protos.Msg{Data: data}})
if err != nil {
st, ok := status.FromError(err)
if !ok {
// 非状态码指定的错误
panic(err)
}
// 状态码指定的错误
println(st.Code(), st.Message())
return
}
println(resp.Msg.Data["username"],"--->",resp.Msg.Data["password"])
}