这个端口对外提供grpc服务,同时对外提供http json格式的服务
需要使用https, http的话得再开一个端口
完整代码如下
package main
import (
"io/ioutil"
"crypto/tls"
"crypto/x509"
"net/http"
"context"
"strings"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"google.golang.org/grpc"
log "github.com/sirupsen/logrus"
"github.com/tmc/grpc-websocket-proxy/wsproxy"
"google.golang.org/grpc/credentials"
pb "hellogw"
)
const (
port = ":50051"
crtFile = "server.crt"
keyFile = "server.key"
)
type server struct{}
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}
func getApiHandle(ctx context.Context) (http.Handler, error) {
mux := runtime.NewServeMux()
/*
dcreds, err := credentials.NewClientTLSFromFile(crtFile, "wjs")
if err != nil {
log.Fatalf("Failed to create client TLS credentials %v", err)
}
opts := []grpc.DialOption{grpc.WithTransportCredentials(dcreds)}
*/
b, err := ioutil.ReadFile(crtFile)
if err != nil {
return nil, err
}
cp := x509.NewCertPool()
if !cp.AppendCertsFromPEM(b) {
return nil, err
}
opts := []grpc.DialOption{grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
// given the grpc-gateway is always connecting to localhost, does
// InsecureSkipVerify=true cause any security issues?
InsecureSkipVerify: true,
RootCAs: cp,
}))}
err = pb.RegisterHelloHandlerFromEndpoint(ctx, mux, "localhost"+port, opts)
if err != nil {
return nil, err
}
// curl -X POST https://localhost:50051/v1/example/echo -d '{"name":"lj"}'
return mux,nil
}
func main() {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
api := grpc.NewServer()
pb.RegisterHelloServer(api, &server{})
var apiHttp http.Handler
handler := http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
if r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
api.ServeHTTP(w, r)
} else {
if apiHttp == nil {
w.WriteHeader(http.StatusNotImplemented)
return
}
apiHttp.ServeHTTP(w, r)
}
})
mux,_ := getApiHandle(ctx)
apiHttp = wsproxy.WebsocketProxy(mux)
err := http.ListenAndServeTLS(port, crtFile, keyFile, handler)
log.Println(err)
}
openssl genrsa -out server.key 2048
openssl req -new -x509 -key server.key -out server.crt -days 365
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:wjs
string is too long, it needs to be less than 2 bytes long
Country Name (2 letter code) [AU]:ch
State or Province Name (full name) [Some-State]:gd
Locality Name (eg, city) []:gz
Organization Name (eg, company) [Internet Widgits Pty Ltd]:zlg
Organizational Unit Name (eg, section) []:zlab
Common Name (e.g. server FQDN or YOUR name) []:wjs
Email Address []:xxx
生成 本示例的rpc文件请参考 grcp 简单示例
下面的函数可以把 grpc 的日志hook过来 打到 logrus 中
"github.com/grpc-ecosystem/go-grpc-middleware"
"github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
"github.com/grpc-ecosystem/go-grpc-middleware/tags"
func gRPCLoggingServerOptions() []grpc.ServerOption {
logrusEntry := log.NewEntry(log.StandardLogger())
logrusOpts := []grpc_logrus.Option{
grpc_logrus.WithLevels(grpc_logrus.DefaultCodeToLevel),
}
return []grpc.ServerOption{
grpc_middleware.WithUnaryServerChain(
grpc_ctxtags.UnaryServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
grpc_logrus.UnaryServerInterceptor(logrusEntry, logrusOpts...),
),
grpc_middleware.WithStreamServerChain(
grpc_ctxtags.StreamServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
grpc_logrus.StreamServerInterceptor(logrusEntry, logrusOpts...),
),
}
}
// 创建 rpc服务的时候 加入日志 hook 函数即可
api := grpc.NewServer(gRPCLoggingServerOptions()...)