






















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/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest
protoc 编译器。可从 https://github.com/protocolbuffers/protobuf/releases 下载预编译二进制(protoc-<version>-win64.zip),解压后将 bin 目录加入系统 PATH。my-microservice/
├── proto/
│ └── user/
│ └── user.proto
├── server/ # gRPC 服务端实现
│ └── main.go
├── gateway/ # gRPC-Gateway HTTP 服务
│ └── main.go
├── gen/ # 生成的代码(可忽略,由脚本生成)
│ └── proto/
│ └── user/
│ ├── user.pb.go
│ ├── user_grpc.pb.go
│ └── user.pb.gw.go
├── go.mod
└── Makefile # 或 generate.bat 用于生成代码
proto/user/user.proto
syntax = "proto3";
package user;
option go_package = "my-microservice/gen/proto/user";
import "google/api/annotations.proto";
service UserService {
rpc GetUser (GetUserRequest) returns (User) {
option (google.api.http) = {
get: "/v1/users/{id}"
};
}
rpc CreateUser (CreateUserRequest) returns (User) {
option (google.api.http) = {
post: "/v1/users"
body: "user"
};
}
}
message GetUserRequest {
string id = 1;
}
message CreateUserRequest {
User user = 1;
}
message User {
string id = 1;
string name = 2;
string email = 3;
}
注意:为了生成 gRPC-Gateway 代码,我们需要导入
google/api/annotations.proto。该文件需要从 googleapis 下载到本地或通过-I指定包含路径。我们将google/api目录放在项目根目录的third_party/googleapis下。
编写一个脚本 generate.bat(Windows 批处理):
@echo off
set PROTOC=protoc
set PROTO_PATH=proto;third_party\googleapis
set OUT_DIR=gen\proto
REM 清理旧生成文件
if exist %OUT_DIR% rmdir /s /q %OUT_DIR%
mkdir %OUT_DIR%
REM 生成 user.pb.go 和 user_grpc.pb.go
%PROTOC% -I=%PROTO_PATH% --go_out=%OUT_DIR% --go_opt=paths=source_relative --go-grpc_out=%OUT_DIR% --go-grpc_opt=paths=source_relative proto/user/user.proto
REM 生成 user.pb.gw.go (gRPC-Gateway)
%PROTOC% -I=%PROTO_PATH% --grpc-gateway_out=%OUT_DIR% --grpc-gateway_opt=paths=source_relative proto/user/user.proto
echo Generation complete.
执行该脚本后,将在 gen/proto/user/ 下得到三个文件:
user.pb.go (消息定义)user_grpc.pb.go (gRPC 客户端/服务端接口)user.pb.gw.go (gRPC-Gateway 反向代理)server/main.go
package main
import (
"context"
"log"
"net"
"my-microservice/gen/proto/user"
"google.golang.org/grpc"
)
type userService struct {
user.UnimplementedUserServiceServer
// 模拟数据库
users map[string]*user.User
}
func (s *userService) GetUser(ctx context.Context, req *user.GetUserRequest) (*user.User, error) {
u, ok := s.users[req.Id]
if !ok {
return nil, nil // 实际应返回 NotFound 错误
}
return u, nil
}
func (s *userService) CreateUser(ctx context.Context, req *user.CreateUserRequest) (*user.User, error) {
u := req.User
if u.Id == "" {
// 生成简单 ID
u.Id = "123" // 生产环境应使用 UUID
}
s.users[u.Id] = u
return u, nil
}
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
user.RegisterUserServiceServer(s, &userService{
users: make(map[string]*user.User),
})
log.Println("gRPC server listening on :50051")
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
gateway/main.go
package main
import (
"context"
"log"
"net/http"
"my-microservice/gen/proto/user"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
func main() {
// 连接到 gRPC 服务端
conn, err := grpc.DialContext(
context.Background(),
"localhost:50051",
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithBlock(),
)
if err != nil {
log.Fatalf("failed to dial gRPC server: %v", err)
}
defer conn.Close()
// 创建 gRPC-Gateway 多路复用器
gwmux := runtime.NewServeMux()
// 注册 UserService 的 HTTP 代理
if err := user.RegisterUserServiceHandler(context.Background(), gwmux, conn); err != nil {
log.Fatalf("failed to register gateway: %v", err)
}
// 启动 HTTP 服务器
addr := ":8080"
log.Printf("HTTP server listening on %s", addr)
if err := http.ListenAndServe(addr, gwmux); err != nil {
log.Fatalf("failed to serve HTTP: %v", err)
}
}
在项目根目录执行:
go mod init my-microservice
go get google.golang.org/grpc
go get google.golang.org/protobuf
go get github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway
go get github.com/grpc-ecosystem/grpc-gateway/v2/runtime
运行 go mod tidy 下载所有依赖。
启动 gRPC 服务端
go run server/main.go
输出:gRPC server listening on :50051
启动 HTTP 网关
go run gateway/main.go
输出:HTTP server listening on :8080
测试 RESTful API
创建用户(POST):
curl -X POST http://localhost:8080/v1/users \
-H "Content-Type: application/json" \
-d '{"id": "1001", "name": "Alice", "email": "alice@example.com"}'
获取用户(GET):
curl http://localhost:8080/v1/users/1001
将收到 JSON 响应,例如:
{"id":"1001","name":"Alice","email":"alice@example.com"}
测试 gRPC 调用(可选)
可以使用 grpcurl 工具:
grpcurl -plaintext -d '{"id":"1001"}' localhost:50051 user.UserService/GetUser
gRPC 作为主通信协议
protoc 生成的接口确保类型安全。gRPC-Gateway 辅助提供 RESTful API
google.api.http 注解定义了 HTTP 方法与路径到 gRPC 方法的映射。protoc-gen-grpc-gateway 根据注解生成一个反向代理服务器,它接收 HTTP/JSON 请求,将其转换为 gRPC 调用,然后将响应转换回 JSON。架构优势
.proto 文件,即可同时生成 gRPC 和 HTTP 接口,避免 API 定义不一致。通过以上步骤,我们成功构建了一个以 gRPC 为核心、同时提供 RESTful 接口的 Go 微服务。完整代码可打包为项目,按需扩展。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。