grpc.md - maoxiaoyue/hypgo GitHub Wiki
pkg/grpc — gRPC Server 封裝
v0.8.5+此套件為 HypGo v0.8.5 新增功能,v0.8.1 版本不包含。
grpc 套件提供 gRPC Server 的統一封裝,包含 listener 管理、TLS、reflection、health check、interceptor(中間件)和 graceful shutdown。
設計理念
HypGo 的 gRPC 與 REST 採用獨立 Server 架構:
pkg/server → HTTP/1.1 + HTTP/2 + HTTP/3(REST + WebSocket) :8080
pkg/grpc → gRPC Server :9090
兩者共用:
app/models/ ← 資料結構
app/services/ ← 業務邏輯
pkg/errors/ ← Error Catalog
pkg/hidb/ ← 資料庫
pkg/logger/ ← 日誌
pkg/config/ ← 設定
快速上手
建立 gRPC 專案
hyp new grpc userservice && cd userservice && go mod tidy
make proto # 編譯 .proto → Go code
go run .
在既有專案中加入 gRPC
import (
hypgrpc "github.com/maoxiaoyue/hypgo/pkg/grpc"
"github.com/maoxiaoyue/hypgo/pkg/grpc/interceptor"
)
grpcSrv := hypgrpc.New(hypgrpc.Config{
Addr: ":9090",
EnableReflection: true,
EnableHealthCheck: true,
}, logger,
grpc.ChainUnaryInterceptor(
interceptor.Recovery(logger),
interceptor.Logger(logger),
),
)
// 註冊服務
pb.RegisterUserServiceServer(grpcSrv.GRPCServer(), &UserServer{})
// 啟動
go grpcSrv.Start()
// 優雅關閉
grpcSrv.GracefulStop()
Config
type Config struct {
Addr string // 監聽地址(預設 ":9090")
TLS *TLSConfig // TLS 配置(nil = plaintext)
EnableReflection bool // 啟用 gRPC reflection(grpcurl 偵錯)
EnableHealthCheck bool // 啟用 gRPC health check 服務
MaxRecvMsgSize int // 最大接收訊息大小(預設 4MB)
MaxSendMsgSize int // 最大發送訊息大小(預設 4MB)
}
type TLSConfig struct {
CertFile string
KeyFile string
}
Server API
| 方法 | 說明 |
|---|---|
New(cfg, logger, ...grpc.ServerOption) |
建立 Server(自動配置 TLS、reflection、health) |
GRPCServer() |
取得底層 *grpc.Server(用於 pb.RegisterXxxServer) |
Start() |
啟動(阻塞) |
GracefulStop() |
優雅關閉(等待進行中的 RPC 完成) |
Stop() |
立即停止 |
Addr() |
取得實際監聽地址 |
IsShuttingDown() |
是否正在關閉(atomic.Bool) |
SetServingStatus(service, status) |
設定 health check 狀態 |
Interceptor(gRPC 中間件)
對應 pkg/middleware/ 的 HTTP 中間件:
| Interceptor | 功能 | 對應 HTTP middleware |
|---|---|---|
interceptor.Recovery(logger) |
Panic → codes.Internal |
middleware.Recovery |
interceptor.Logger(logger) |
記錄方法、耗時、狀態碼 | middleware.Logger |
interceptor.Auth(authFn, skipMethods...) |
Token 驗證 + context 注入 | middleware.JWT |
interceptor.RateLimit(config) |
IP 限流 + 背景清理 | middleware.RateLimit |
使用 Interceptor
s := hypgrpc.New(cfg, logger,
grpc.ChainUnaryInterceptor(
interceptor.Recovery(logger), // 最外層:捕獲 panic
interceptor.Logger(logger), // 記錄每個 RPC
interceptor.Auth(myAuthFunc, // 驗證 token
"/grpc.health.v1.Health/Check", // 跳過 health check
),
interceptor.RateLimit(interceptor.RateLimitConfig{
MaxRequests: 100, // 每分鐘 100 次
Window: time.Minute,
}),
),
)
Auth Interceptor 詳解
// 定義驗證函式
authFn := func(ctx context.Context, token string) (interface{}, error) {
// 驗證 JWT token
claims, err := jwt.Validate(token)
if err != nil {
return nil, err // → codes.Unauthenticated
}
return claims, nil // 存入 context
}
// 在 RPC handler 中取出使用者
func (s *Server) GetUser(ctx context.Context, req *pb.GetUserReq) (*pb.UserResp, error) {
user, ok := interceptor.UserFromContext(ctx)
if !ok {
return nil, status.Error(codes.Internal, "no user in context")
}
// user 是 authFn 回傳的物件
}
RateLimit 安全設計
- 根據客戶端 IP 限流(從
peer.FromContext取得) - 背景 goroutine 定期清理過期 key(預設每 5 分鐘)
- 超過限制回傳
codes.ResourceExhausted
專案結構
hyp new grpc userservice
userservice/
├── app/
│ ├── proto/userservicepb/
│ │ └── userservice.proto ← Protobuf 定義
│ ├── rpc/
│ │ └── userservice_server.go ← gRPC 服務實作
│ ├── models/ ← 共用資料結構
│ ├── services/ ← 共用業務邏輯
│ └── config/config.yaml
├── main.go
├── Makefile ← make proto
└── go.mod
新增更多服務
hyp generate proto order
# → app/proto/orderpb/order.proto
# → app/rpc/order_server.go
與 REST 的共存
同一個專案可以同時有 REST 和 gRPC:
func main() {
// REST Server
srv := server.New(cfg, log)
routers.Setup(srv.Router())
// gRPC Server
grpcSrv := hypgrpc.New(hypgrpc.Config{Addr: ":9090"}, log)
pb.RegisterUserServiceServer(grpcSrv.GRPCServer(), &UserServer{})
// 同時啟動
go srv.Start() // :8080 REST
go grpcSrv.Start() // :9090 gRPC
// 優雅關閉
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
srv.Shutdown(ctx)
grpcSrv.GracefulStop()
}
共用 Service 層
Controller (REST) ─┐
├─→ UserService (app/services/) ─→ Database
RPC Handler (gRPC) ─┘
Controller 和 RPC handler 都是薄 adapter,真正的邏輯在 app/services/ 中共用。
安全
- TLS:支援 mTLS,MinVersion = TLS 1.2
- Auth:未提供 token →
codes.Unauthenticated(安全預設) - Auth skip:可跳過不需驗證的方法(如 Health check)
- RateLimit:背景清理防記憶體洩漏
- Recovery:panic 不 crash,回傳
codes.Internal - GracefulStop:
atomic.Bool防止重複關閉
必要工具
gRPC 開發需要安裝:
# protoc 編譯器
# https://github.com/protocolbuffers/protobuf/releases
# Go protobuf 插件
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
# 偵錯工具(可選)
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
測試
# 啟動 server 後,用 grpcurl 測試
grpcurl -plaintext localhost:9090 list
grpcurl -plaintext -d '{"name":"test"}' localhost:9090 userservicepb.UserserviceService/CreateUserservice