改版百度不收录网站,想要网站推广页,temu跨境电商入驻,不屏蔽网站的浏览器yaml定义http规则#xff0c;和自定义实现网关路由
proto定义http规则总归是麻烦的#xff0c;因为proto文件还是定义消息#xff0c;grpc接口好一些。配置http规则有更好的方式。我们可以使用yaml文件定义接口的http规则。 同时有些接口不是只是让网关转发这么简单 有时需…yaml定义http规则和自定义实现网关路由
proto定义http规则总归是麻烦的因为proto文件还是定义消息grpc接口好一些。配置http规则有更好的方式。我们可以使用yaml文件定义接口的http规则。 同时有些接口不是只是让网关转发这么简单 有时需要自己定网关接口handler
yaml定义http规则
type: google.api.Service
config_version: 3http:rules:# {package}.{message}.{method}- selector: user.User.Getget: /user/{id}- selector: user.User.AddOrUpdatepost: /userbody: *additional_bindings:- put: /userbody: *- patch: /userbody: addr- selector: user.User.Deletedelete: /user/{id}
proto文件
syntax proto3;
package user;
option go_package user/proto;message Member{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;
}message UploadRequest {int64 size 1;bytes content 2;
}
message UploadResponse {string filePath 1[json_name file_path];
}
service User{rpc Get(Member) returns (Member) {}rpc AddOrUpdate(Member) returns (Member) { }rpc Delete(Member) returns (Member) {}rpc Upload(stream UploadRequest) returns (UploadResponse){}
}
生成消息,grpc,网关
# 生成message
protoc --proto_pathproto --go_outproto --go_optpathssource_relative proto/user.proto
# 生成grpc service
protoc --proto_pathproto --go-grpc_outproto --go-grpc_optpathssource_relative proto/user.proto
#生成gateway
protoc --proto_pathproto --grpc-gateway_outproto --grpc-gateway_opt logtostderrtrue --grpc-gateway_opt pathssource_relative --grpc-gateway_opt grpc_api_configurationproto/user.yaml proto/user.proto参考grpc-gateway入门中的启动代码就能调用对应接口啦
自定义实现网关路由
在生成gateway后前面proto文件中我们预留了一个文件上传grpc接口。然后在yaml中我们是没有定义对应http规则。 所以需要自定义实现对应的网关路由来应对复杂的业务情况。
gateway.go
通过mux.HandlePath添加自定义处理的路由和对应handler函数
package gatewayimport (contextflaggoogle.golang.org/grpc/health/grpc_health_v1net/httpuser/user-server/gateway/middlewaregithub.com/grpc-ecosystem/grpc-gateway/v2/runtimegoogle.golang.org/grpcgoogle.golang.org/grpc/credentials/insecuregw user/proto
)var (grpcServerEndpoint flag.String(grpc-server-endpoint, localhost:50051, gRPC server endpoint)
)func Run() error {ctx : context.Background()ctx, cancel : context.WithCancel(ctx)defer cancel()inComingOpt : runtime.WithIncomingHeaderMatcher(func(s string) (string, bool) {switch s {case Service-Authorization:return service-authorization, truedefault:return , false}return , false})//创建连接,用于健康检查conn, err : grpc.Dial(*grpcServerEndpoint, grpc.WithTransportCredentials(insecure.NewCredentials()))if err ! nil {return err}mux : runtime.NewServeMux(inComingOpt, runtime.WithHealthzEndpoint(grpc_health_v1.NewHealthClient(conn)))//添加自定义处理函数mux.HandlePath(POST, /upload, uploadHandler)handler : middleware.Cors(mux)opts : []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}err gw.RegisterUserHandlerFromEndpoint(ctx, mux, *grpcServerEndpoint, opts)if err ! nil {return err}return http.ListenAndServe(:8081, handler)
}
upload.go
写对应网关需要注册的handler
package gatewayimport (contextfmtgithub.com/golang/protobuf/jsonpbgoogle.golang.org/grpcgoogle.golang.org/grpc/credentials/insecuregoogle.golang.org/grpc/metadataionet/httpuser/proto
)func uploadHandler(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {serviceAuthorization : r.Header.Get(Service-Authorization)fmt.Println(serviceAuthorization)err : r.ParseForm()if err ! nil {http.Error(w, fmt.Sprintf(上传失败%s, err.Error()), http.StatusInternalServerError)return}f, header, err : r.FormFile(attachment)if err ! nil {http.Error(w, fmt.Sprintf(上传失败%s, err.Error()), http.StatusInternalServerError)return}defer f.Close()conn, err : grpc.Dial(*grpcServerEndpoint, grpc.WithTransportCredentials(insecure.NewCredentials()))if err ! nil {http.Error(w, fmt.Sprintf(上传失败%s, err.Error()), http.StatusInternalServerError)return}defer conn.Close()c : proto.NewUserClient(conn)ctx : context.Background()ctx metadata.NewOutgoingContext(ctx, metadata.New(map[string]string{file_name: header.Filename, service-authorization: serviceAuthorization}))stream, err : c.Upload(ctx)if err ! nil {http.Error(w, fmt.Sprintf(上传失败%s, err.Error()), http.StatusInternalServerError)return}buf : make([]byte, 100)for {n, err : f.Read(buf)if err ! nil err ! io.EOF {http.Error(w, fmt.Sprintf(上传失败%s, err.Error()), http.StatusInternalServerError)return}if n 0 {break}stream.Send(proto.UploadRequest{Content: buf[:n],Size: int64(n),})}res, err : stream.CloseAndRecv()if err ! nil {http.Error(w, fmt.Sprintf(上传失败%s, err.Error()), http.StatusInternalServerError)return}m : jsonpb.Marshaler{}str, err : m.MarshalToString(res)if err ! nil {http.Error(w, fmt.Sprintf(上传失败%s, err.Error()), http.StatusInternalServerError)return}w.Header().Add(Content-Type, application/json)fmt.Fprint(w, str)
}
重新启动即可