golang工程— grpc-gateway健康检查和跨域配置

grpc健康检查网关跨域配置

grpc健康检查

grpc健康检查使用

服务端配置
import (
    "google.golang.org/grpc/health"
    "google.golang.org/grpc/health/grpc_health_v1"
)

//添加健康检查服务,多路复用
grpc_health_v1.RegisterHealthServer(s, health.NewServer())
网关配置

gateway.go

package gateway

import (
    "context"
    "flag"
    "fmt"
    "google.golang.org/grpc/health/grpc_health_v1"
    "net/http"
    "user/user-server/gateway/middleware"

    "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
    _ "google.golang.org/grpc/grpclog"

    gw "user/proto"  // Update
)

var (
    // command-line options:
    // gRPC server endpoint
    grpcServerEndpoint = flag.String("grpc-server-endpoint",  "localhost:50051", "gRPC server endpoint")
)

func Run() error {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()
    // 请求时,将http header中某些字段转发到grpc上下文
    inComingOpt :=  runtime.WithIncomingHeaderMatcher(func(s string) (string, bool) {
        fmt.Println("header:" + s)
        switch s {
        case "Service-Authorization":
            fmt.Println("Service-Authorization hit")
            return "Service-Authorization", true
        default:
            return "", false
        }
    })
    // 响应后,grpc上下文转发到http头部
    outGoingOpt := runtime.WithOutgoingHeaderMatcher(func(s string) (string, bool) {
       return "", false
    })


    //创建连接,用于健康检查
    conn, err := grpc.Dial(*grpcServerEndpoint, grpc.WithTransportCredentials(insecure.NewCredentials()))
    if err != nil {
        return err
    }


    // Register gRPC server endpoint
    // Note: Make sure the gRPC server is running properly and accessible
    // runtime.WithHealthEndpointAt() 指定路径, 转发Header到grpc上下文在这是不生效的inCommingOpt 是不生效的,因为我们在这弄了个客户端,需要手动转发操作。或者排除掉,我们这选择排除掉
    mux := runtime.NewServeMux(inComingOpt, outGoingOpt, 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
    }

    // Start HTTP server (and proxy calls to gRPC server endpoint)
    return http.ListenAndServe(":8081", handler)
}


如果网关中设置了拦截器之类的进行鉴权判断,可以通过FullName="/grpc.health.v1.Health/Check"去忽略鉴权

监控检查默认请求 http://localhost:8081/healthz

grpc网关跨域配置

采用中间件的形式封装httphandler

package middleware

import "net/http"

func Cors(handler http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        method := r.Method
        origin := r.Header.Get("Origin")
        if origin != "" {
            // 允许来源配置
            w.Header().Set("Access-Control-Allow-Origin", "*") // 可将将 * 替换为指定的域名
            w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE, PATCH")
            w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
            w.Header().Set("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
            w.Header().Set("Access-Control-Allow-Credentials", "true")
        }
        if method == "OPTIONS" {
            w.WriteHeader(http.StatusNoContent)
            return
        }
        handler.ServeHTTP(w, r)
    })
}

然后修改gateway

gateway.go

package gateway

import (
    "context"
    "flag"
    "fmt"
    "google.golang.org/grpc/health/grpc_health_v1"
    "net/http"
    "user/user-server/gateway/middleware"

    "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
    _ "google.golang.org/grpc/grpclog"

    gw "user/proto"  // Update
)

var (
    // command-line options:
    // gRPC server endpoint
    grpcServerEndpoint = flag.String("grpc-server-endpoint",  "localhost:50051", "gRPC server endpoint")
)

func Run() error {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()
    // 请求时,将http header中某些字段转发到grpc上下文
    inComingOpt :=  runtime.WithIncomingHeaderMatcher(func(s string) (string, bool) {
        fmt.Println("header:" + s)
        switch s {
        case "Service-Authorization":
            fmt.Println("Service-Authorization hit")
            return "Service-Authorization", true
        default:
            return "", false
        }
    })
    // 响应后,grpc上下文转发到http头部
    outGoingOpt := runtime.WithOutgoingHeaderMatcher(func(s string) (string, bool) {
       return "", false
    })


    //创建连接,用于健康检查
    conn, err := grpc.Dial(*grpcServerEndpoint, grpc.WithTransportCredentials(insecure.NewCredentials()))
    if err != nil {
        return err
    }


    // Register gRPC server endpoint
    // Note: Make sure the gRPC server is running properly and accessible
    // runtime.WithHealthEndpointAt() 指定路径, 转发Header到grpc上下文在这是不生效的inCommingOpt 是不生效的,因为我们在这弄了个客户端,需要手动转发操作。或者排除掉,我们这选择排除掉
    mux := runtime.NewServeMux(inComingOpt, outGoingOpt, 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
    }

    // Start HTTP server (and proxy calls to gRPC server endpoint)
    return http.ListenAndServe(":8081", handler)
}


更多grpc跨域配置的内容见

[gin中间件编程与跨域配置](

在Go语言中,GRPC Gateway是一个工具,它允许你将现有的gRPC服务转换成HTTP API,而无需修改服务端代码。下面是一个简单的gRPC到HTTP的示例,我们将创建一个简单的`HelloService` gRPC服务,并通过Gateway将其暴露为RESTful API。 首先,安装必要的依赖: ```sh go get google.golang.org/grpc go get github.com/grpc-ecosystem/grpc-gateway/v2 ``` 然后,假设我们有一个名为`hello.proto`的协议定义文件,内容如下: ```protobuf syntax = "proto3"; package hello; service Hello { rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; } ``` 接下来,生成服务器客户端代码: ```sh protoc -I=$GOPATH/src -I=$SRC_DIR -o $GOPATH/src/hello/hello.pb.go $SRC_DIR/hello.proto protoc -I=$GOPATH/src -I=$SRC_DIR --grpc-gateway_out=logtostderr=true:. $SRC_DIR/hello.proto ``` 创建一个简单的`server/main.go`: ```go package main import ( "context" "fmt" "log" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "google.golang.org/grpc" _ "github.com/grpc-ecosystem/grpc-gateway/v2/examples/helloworld" "golang.org/x/net/context" "hello/hellopb" ) func main() { lis, err := grpc.Listen("0.0.0.0:50051", nil) if err != nil { log.Fatalf("failed to listen: %v", err) } srv := grpc.NewServer() hellopb.RegisterHelloServer(srv, &HelloServiceImpl{}) runtime.ServeGRPC(mux, srv) fmt.Println("Starting server on port 50051") if err := lis.Serve(); err != nil { log.Fatal(err) } } type HelloServiceImpl struct{} func (h *HelloServiceImpl) SayHello(ctx context.Context, req *hellopb.HelloRequest) (*hellopb.HelloReply, error) { return &hellopb.HelloReply{Message: fmt.Sprintf("Hello, %s!", req.Name)}, nil } ``` 最后,在`gateway/gateway.yaml`里配置路由: ```yaml # gateway.yaml openapi: 3.0.2 info: title: Simple Greeting Service version: 1.0.0 servers: - url: http://localhost:8000/ paths: /hello: post: summary: Greet a user operationId: SayHello requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: The user's name responses: '200': description: A successful response with the greeting. content: application/json: schema: type: object properties: message: type: string ``` 运行`server``gateway`: ```sh go run server/main.go go run gateway/gateway_main.go ``` 现在你可以访问`http://localhost:8000/hello`并发送POST请求,数据包含`name`字段,服务器会返回一个问候消息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值