option自定义http规则和http body响应
简介
本篇接上文
golang 工程组件:grpc-gateway 环境安装+默认网关测试
默认网关配置终究是难用,本篇介绍一下proto里采用option自定义http规则以及让网关返回http
响应而不是我们定义的grpc
响应
option定义http规则和httpbody响应
引入库。可以直接拷贝grpc-gateway源码下google文件夹到项目下
import "google/api/annotations.proto";
import "google/api/httpbody.proto";
import "google/protobuf/empty.proto";
user.proto
syntax = "proto3";
package echo;
option go_package = "echo/proto";
import "google/api/annotations.proto";
import "google/api/httpbody.proto";
import "google/protobuf/empty.proto";
message User{
int64 id = 1;
// 改成下划线形式
string userName = 2[json_name="user_name"];
int32 age = 3;
string phone = 4;
Addr addr = 5;
}
message Addr {
string province = 1;
string city = 2;
string county = 3;
}
service Echo{
rpc Get(User) returns (User) {
//get请求
option (google.api.http) = {
get: "/echo/user/{id}"
};
}
rpc AddOrUpdate(User) returns (User) {
option (google.api.http) = {
post: "/echo/user"
// * 表示接受user所有字段
body: "*"
additional_bindings {
put: "/echo/user"
body: "*"
}
//patch 请求,只更新部分字段
additional_bindings {
patch: "/echo/user"
body: "addr"
}
};
}
rpc Delete(User) returns (User) {
option (google.api.http) = {
delete: "/echo/user/{id}"
};
}
// httpbody响应,前面是grpc定义的消息
rpc List(google.p服务器托管网rotobuf.Empty) returns (stream google.api.HttpBody) {
option (google.api.http) = {
get: "/echo/user/list"
};
}
}
对应grpc实现
server.go
package server
import (
"context"
"echo/proto"
"fmt"
"github.com/golang/protobuf/jsonpb"
_ "github.com/golang/protobuf/jsonpb"
"google.golang.org/genproto/googleapis/api/httpbody"
_ "google.golang.org/genproto/googleapis/api/httpbody"
"google.golang.org/protobuf/types/known/emptypb"
_ "google.golang.org/protobuf/t服务器托管网ypes/known/emptypb"
)
type echoServer struct {
proto.UnimplementedEchoServer
}
func NewServer() proto.EchoServer {
return &echoServer{}
}
func (s *echoServer) Get(ctx context.Context, in *proto.User) (*proto.User, error) {
fmt.Printf("%+vn", in)
return in, nil
}
func (s *echoServer) AddOrUpdate(ctx context.Context, in *proto.User) (*proto.User, error) {
fmt.Printf("%+vn", in)
return in, nil
}
func (s *echoServer) Delete(ctx context.Context, in *proto.User) (*proto.User, error) {
fmt.Printf("%+vn", in)
return in, nil
}
func (s *echoServer) List(in *emptypb.Empty, stream proto.Echo_ListServer) error {
userList := []*proto.User{
{
Id: 1,
UserName: "test1",
Addr: &proto.Addr{
Province: "深圳1",
},
},
{
Id: 2,
UserName: "test2",
Addr: &proto.Addr{
Province: "深圳2",
},
},
{
Id: 3,
UserName: "test3",
Addr: &proto.Addr{
Province: "深圳3",
},
},
}
for _, u := range userList {
//jsonpb库序列化返回的才是下划线形式。 json序列化不读tag里定义
m := jsonpb.Marshaler{}
data, _ := m.MarshalToString(u)
msg := &httpbody.HttpBody{
ContentType: "application/json",
Data: []byte(data),
}
stream.Send(msg)
}
return nil
}
启动后按对应路由访问即可。 网关和启动源码在上文里
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
项目的需求来源有很多方面,最终由产品经理整理出来哪些要做,哪些不做。我前面说过需求评审时,要讲清楚这次版本的目的是什么。这些要做的功能就是达成目的的手段。 一般情况下,我们都默认产品或技术总监给需求定优先级。比如优先级高、中、低。实际上这样分还不够细,优先级高…