golang工程——grpc-gateway 转发http header中自定义字段到grpc上下文元数据

这篇具有很好参考价值的文章主要介绍了golang工程——grpc-gateway 转发http header中自定义字段到grpc上下文元数据。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

http header 转发到 grpc上下文

grpc网关可以将请求体内容转发到grpc对应消息中。那如何获取http header头中的信息,本文将介绍如何将http header转发到grpc上下文并采用拦截器,获取http header中的内容。 有些http header中的内置字段是会转发的比如Authorization,但是狠多自定义字段是转发不了的。

本文实现http header中自定义字段转发到grpc上下文并采用拦截器做个简单鉴权

代码可以参考前面几篇grpc-gateway博客

grpc-gateway入门,环境+简单案例

grpc-gateway proto定义http路由

grpc-gateway定义http路由

网关代码修改

如果要转发http header中的自定义内容,生成的网关代码需要进行修改,增加一些网关服务器选项

  • runtime.WithIncomingHeaderMatcher: 请求http header 设置转发哪些到grpc上下文
  • runtime.WithOutgoingHeaderMatcher: 响应后,grpc上下文转发到http头部

gateway.go

package gateway

import (
    "context"
    "flag"
    "fmt"
    "net/http"

    "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
    })
    // Register gRPC server endpoint
    // Note: Make sure the gRPC server is running properly and accessible
    mux := runtime.NewServeMux(inComingOpt, outGoingOpt)
    
    //添加文件上传处理函数
    mux.HandlePath("POST", "/upload", uploadHandler)
    
    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", mux)
}


文件上传接口修改,因为这是自定义的网关路由接口,需要自己将Header中的字段转发到grpc中

upload.go

package gateway

import (
    "context"
    "fmt"
    "github.com/golang/protobuf/jsonpb"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
    "google.golang.org/grpc/metadata"
    "io"
    "net/http"
    "user/proto"
)

func uploadHandler(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {
    // 先从request解析文件
    err := r.ParseForm()
    if err != nil {
        http.Error(w, fmt.Sprintf("上传失败:%s", err.Error()), http.StatusInternalServerError)
    }

    f, header, err :=r.FormFile("attachment")

    if err != nil {
        http.Error(w, fmt.Sprintf("上传失败:%s", err.Error()), http.StatusInternalServerError)
    }

    defer f.Close()

    // 访问grpc server端, 实际生产用连接池

    conn, err := grpc.Dial(*grpcServerEndpoint, grpc.WithTransportCredentials(insecure.NewCredentials()))

    if err != nil {
        http.Error(w, fmt.Sprintf("上传失败:%s", err.Error()), http.StatusInternalServerError)
    }

    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":r.Header.Get("Service-Authorization"),
    }))
    stream, err := c.Upload(ctx)

    if err != nil {
        http.Error(w, fmt.Sprintf("上传失败:%s", err.Error()), http.StatusInternalServerError)
    }

    // 读文件流 转发给grpc
    buf := make([]byte, 512)
    for {
        n, err := f.Read(buf)
        if err != nil && err != io.EOF{
            http.Error(w, fmt.Sprintf("上传失败:%s", err.Error()), http.StatusInternalServerError)
        }
        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)
    }

    m := jsonpb.Marshaler{}
    str, _ := m.MarshalToString(res)
    if err != nil {
        http.Error(w, fmt.Sprintf("上传失败:%s", err.Error()), http.StatusInternalServerError)
    }

    w.Header().Add("Content-Type", "application/json")
    fmt.Fprintf(w, str)

}
grpc服务代码修改

拦截器,从上下文中获取元数据进行业务操作即可

interceptor.go

package server

import (
    "context"
    "errors"
    "fmt"
    "google.golang.org/grpc"
    "google.golang.org/grpc/metadata"
    "strings"
)

func UnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
    err = auth(ctx)
    if err != nil {
        return nil, err
    }

    return handler(ctx, req)
}

func StreamInterceptor(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
    err := auth(ss.Context())
    if err != nil {
        return err
    }
    return handler(srv, ss)
}


func auth(ctx context.Context) error {
    md, ok := metadata.FromIncomingContext(ctx)
    fmt.Println("meta:", md)
    // 实际应用中,返回前端提示需模糊化,详细错误可以打印日志
    if !ok {
        return errors.New("获取元数据失败,身份校验失败")
    }
    // 转发过来都是小写
    authorization := md["service-authorization"]
    if len(authorization) < 1 {
        return errors.New("获取身份令牌失败,身份校验失败")
    }
    token := strings.TrimPrefix(authorization[0], "Bearer ")
    if token != bearerToken {
        return errors.New("身份令牌对比失败,身份校验失败")
    }
    return nil
}

// 测试用
var bearerToken = "sdfdlsdhgeiasdxzasqqqy2ybfhhu2gyvb"

并将拦截器注册到grpc服务中

s := grpc.NewServer(grpc.UnaryInterceptor(server.UnaryInterceptor), grpc.StreamInterceptor(server.StreamInterceptor))

重点还是网关代码修改,增加转发header的逻辑文章来源地址https://www.toymoban.com/news/detail-717402.html

到了这里,关于golang工程——grpc-gateway 转发http header中自定义字段到grpc上下文元数据的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • gRPC-GateWay Swagger 实战

    上一次我们分享了关于 gRPC-Gateway 快速实战 ,可以查看地址来进行回顾 : 也可以查看关于 gRPC 的历史文章: gRPC介绍 gRPC 客户端调用服务端需要连接池吗? gRPC的拦截器 gRPC的认证 分享一下 gRPC- HTTP网关 I 今天主要是分享关于 gRPC-Gateway Swagger 的实战部分,文章大体分为如下几个

    2024年02月10日
    浏览(39)
  • golang 通用的 grpc http 基础开发框架

    golang 通用的 grpc http 基础开发框架 仓库地址: https://github.com/webws/go-moda 仓库一直在更新,欢迎大家吐槽和指点 transport: 集成 http(echo、gin)和 grpc。 tracing: openTelemetry 实现微务链路追踪 pprof: 分析性能 config: 通用的配置文件读取模块,支持 toml、yaml 和 json 格式。 logger: 日志系统

    2024年02月10日
    浏览(39)
  • gRPC之gRPC Gateway

    etcd3 API全面升级为gRPC后,同时要提供REST API服务,维护两个版本的服务显然不太合理,所以 grpc-gateway 诞生了。通过protobuf的自定义option实现了一个网关,服务端同时开启gRPC和HTTP服务, HTTP服务接收客户端请求后转换为grpc请求数据,获取响应后转为json数据返回给客户端。结构

    2024年02月07日
    浏览(41)
  • nginx转发headers内容丢失解决办法

    开发网关项目时,在请求时往请求头header中放入了签名sign_key信息,在接收请求时再从header中拿出,在本地调试时是可以的,但上线之后通过Nginx代理之后发现拿不到。 nginx代理默认会把header中参数的 \\\"_\\\" 下划线去掉,所以后台服务器后就获取不到带\\\"_\\\"线的参数名。需要在htt

    2024年02月11日
    浏览(65)
  • [golang 微服务] 4. gRPC介绍,Protobuf结合gRPC 创建微服务

    gRPC是一个 高性能 、 开源 和 通用 的 RPC 框架 , 面向移动端 和 HTTP/2 设计,目前提供 C、Java 和 Go语言版本,分别是:grpc, grpc-java, grpc-go, 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持 (1).提供几乎所有主流语言的实现, 打破语言隔阂 (2). 基于 HTTP/2 标准设计

    2024年02月04日
    浏览(46)
  • golang grpc配置使用实战教程

    RPC是远程过程调用(Remote Procedure Call)的缩写形式, RPC 的主要功能目标是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。通俗地讲, 使用RPC进行通信,调用远程函数就像调用本地函数一样,RPC底层会做好数据的序列化与传输。

    2024年02月03日
    浏览(44)
  • nginx 把所有请求转发到另一个端口, 并添加header头,怎么配置

    要将nginx中的所有请求转发到另一个端口,可以使用nginx的 proxy_pass 指令来实现。以下是配置文件示例: 在上述配置中,我们创建了一个服务器块,并监听80端口,这是常见的HTTP请求端口。 server_name 指令用于指定该服务器块适用的域名,你需要将其替换为你的域名。 location

    2024年02月12日
    浏览(38)
  • gateway路由转发

    今天学习的时候看到yml中有关与gateway的配置没看懂 然后就去网上学习了一下,分享我一下我的学习成果吧, gateway可以开启从注册中心转发路由 然后就是有一个routes的配置 这边的 predicates 就是你访问gateway路由端口后的路径,类似于我访问 http://localhost:gateway端口/case/api/sys

    2024年02月12日
    浏览(34)
  • Gateway路由转发,报404错误

    项目使用SpringCloud分为多个微服务,在使用Gateway进行路由转发时,找不到对应的微服务模块,导致返回404报错。 当用户发出请求达到 GateWay 之后,会通过一些匹配条件,定位到真正的服务节点,而 Predicate就是匹配条件 。当满足条件后才会进行转发路由,如果是多个,那么

    2024年02月11日
    浏览(42)
  • golang gRPC:根据.protobuf文件生成go代码

    安装 protoc 编译器。如果没有安装,可以参考官方文档进行安装。 使用 protoc 命令生成 gRPC 代码: 此命令将生成 .pb.go 和 _grpc.pb.go 文件,其中包含 protobuf 和 gRPC 的代码实现. –go_out选项会生成纯粹的Protocol Buffer消息代码,这包括Go语言的消息结构体和一些辅助方法。如果你只

    2024年02月14日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包