grpc之实现restful api
- 安装插件
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
- 克隆 googleapis,里面有需要用到的proto文件
git clone https://github.com/googleapis/googleapis.git
这个可能会超时,多get几次
go get github.com/grpc-ecosystem/grpc-gateway/v2/runtime
- 还是以之前golang项目为基础,在proto文件下新建rest文件夹,添加rest.proto
syntax = "proto3";
import "google/api/annotations.proto";
package rest;
option go_package = "/";
// The greeting service definition
service Rest {
// Sends a greeting
rpc Hello (HelloRequest) returns (HelloReply) {
option (google.api.http) = {
post: "/hello"
body: "*"
};
}
}
// The request message containing the user's name
message HelloRequest {
string Name = 1;
}
// The response message containing the greetings
message HelloReply {
string Message = 1;
}
比之前的rpc方法多了
option (google.api.http) = {
post: "/hello"
body: "*"
};
这个就是restful请求的url。 这里就用到刚才克隆的googleapis,需要两个特殊设置。 在goland里面需要手动添加一下地址,不然就找不到文件 然后就是命令行生成代码
protoc --proto_path=/home/wms/project/github/googleapis --proto_path=. --go_out=. --go-grpc_out=. --grpc-gateway_out=. rest.proto
会比之前的多生成一个gw文件 4. 在server文件夹实现rpc方法
package server
import (
"context"
res "grpc-golang/proto/rest"
)
type Rest struct {
res.UnimplementedRestServer
}
func (s *Rest) Hello(ctx context.Context, in *res.HelloRequest) (*res.HelloReply, error) {
return &res.HelloReply{Message: in.Name + " world"}, nil
}
- 然后注册服务
import ress "grpc-golang/proto/rest"
ress.RegisterRestServer(s, &Rest{})
- 新建一个server_rest.go以区别之前的
package main
import (
"context"
"flag"
"fmt"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
ress "grpc-golang/proto/rest"
"grpc-golang/server"
"log"
"net"
"net/http"
)
func main() {
flag.Parse()
lis, err := net.Listen("tcp", ":50053")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := server.Register()
fmt.Println("*************************************************")
fmt.Println(" rpc")
fmt.Println(" 服务端口", lis.Addr())
fmt.Println("*************************************************")
//if err := s.Serve(lis); err != nil {
// log.Fatalf("failed to serve: %v", err)
//}
go func() {
log.Fatalln(s.Serve(lis))
}()
conn, err := grpc.DialContext(
context.Background(),
"0.0.0.0:50053",
grpc.WithBlock(),
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
log.Fatalln("Failed to dial server:", err)
}
gwmux := runtime.NewServeMux()
// Register Greeter
err = ress.RegisterRestHandler(context.Background(), gwmux, conn)
if err != nil {
log.Fatalln("Failed to register gateway:", err)
}
gwServer := &http.Server{
Addr: ":8090",
Handler: gwmux,
}
log.Println("Serving gRPC-Gateway on http://0.0.0.0:8090")
log.Fatalln(gwServer.ListenAndServe())
}
启动服务
go run server_rest.go
- 用浏览器访问http://192.168.2.127:8090/hello报错,然后改用postman请求 可以看到接口请求是成功的,只是需要授权才能访问。
- 稍微调整下server_rest.go
gwmux := runtime.NewServeMux()
改成
gwmux := runtime.NewServeMux(
// handle incoming headers
runtime.WithMetadata(func(ctx context.Context, request *http.Request) metadata.MD {
header := request.Header.Get("accessToken")
// send all the headers received from the client
md := metadata.Pairs("accessToken", header)
return md
}))