当前位置: 首页 > news >正文

网站视频不能下载怎么保存视频/广告优化师怎么学

网站视频不能下载怎么保存视频,广告优化师怎么学,企业网页页面设计,石碣做网站文章目录前言一、工程实践中如何更好的使用proto文件?二、protoc命令如何查询依赖的proto文件以及执行原理1. protoc命令如何查询依赖的proto文件2. protoc执行的插件加载原理是什么?3. proto文件中的package和go_package的作用三、protoc插件开发原理体…

文章目录

  • 前言
  • 一、工程实践中如何更好的使用proto文件?
  • 二、protoc命令如何查询依赖的proto文件以及执行原理
    • 1. protoc命令如何查询依赖的proto文件
    • 2. protoc执行的插件加载原理是什么?
    • 3. proto文件中的package和go_package的作用
  • 三、protoc插件开发原理
    • 体验流程
  • 四、gin转发到grpc服务的原理和实现
    • 1. 自己写.pb.go体验其原理
    • 2. 细节纠错
  • 五、go的template实现动态生成代码
  • 六、protoc生成gin的插件


前言

目的:proto映射成gin,把rpc的服务映射成http的服务

使用 proto 文件的实践技巧:

  1. 将 proto 文件作为项目的 API 定义:将所有的 RPC 接口和消息结构定义在 proto 文件中,并将其作为项目的 API 文档。这样可以使得代码更加清晰易懂,并且可以方便地自动生成文档。

  2. 使用 proto3 语法:proto3 是 proto 文件的最新版本,它的语法更加简洁,易于理解和维护。与 proto2 相比,proto3 删除了一些不必要的特性,减少了重复代码,并且更加安全。

  3. 采用一致的命名规范:在 proto 文件中定义的消息类型、字段名称和 RPC 接口名称应该采用一致的命名规范,以便于代码的阅读和维护。

  4. 使用 well-known types:proto 文件提供了许多 well-known types,这些类型已经在很多开源库和框架中得到了广泛的使用,例如 timestamp、duration、empty 等。在需要使用这些类型的场景下,应该优先选择它们,以减少代码的复杂度。

  5. 生成代码:在 Go 语言中,可以使用 protoc 工具来生成序列化和反序列化代码、RPC 客户端和服务端代码等。可以通过设置 protoc 的插件来生成不同类型的代码,例如 grpc-go 插件可以生成 gRPC 相关的代码。

  6. 使用版本控制:proto 文件是代码的一部分,应该与代码一同纳入版本控制系统中,并且应该使用标准的代码审查流程来确保代码的质量和可维护性。

  7. 使用测试:在编写 proto 文件时,应该编写相应的单元测试和集成测试,以确保 proto 文件的正确性和一致性。可以使用 Prototest 等测试框架来编写测试用例。


一、工程实践中如何更好的使用proto文件?

Kratos 一套轻量级 Go 微服务框架,包含大量微服务相关框架及工具:https://go-kratos.dev/

  1. proto文件可以用作http和rpc服务的生成标注写法
    我写了一个gin的服务,我还要手动去维护api文档,手动去yapi上维护 后期维护和迭代很简单, 改了任何代码你都可以直接生成api
    可以直接将proto生成swagger文件,然后一键导入到yapi上,这样就可以直接在yapi上查看api文档了
  2. 在kratos中对proto的依赖更加重, 可以用来定义一些错误码, 并生成go源码直接使用
  3. kratos甚至将配置文件都给你映射成proto文件
    业内很多框架都开始逐步接受将proto文件作为核心的标准去写一系列插件去自动生成代码
    proto validate

go-zero更溜,goctl,保姆式的框架 api文件 go-zero和kratos的一套设计理念


二、protoc命令如何查询依赖的proto文件以及执行原理

1. protoc命令如何查询依赖的proto文件

中文官方文档:https://go-kratos.dev/docs/component/api

安装方式按照官方即可

官方示例proto:

syntax = "proto3";package helloworld.v1;import "google/api/annotations.proto";option go_package = "github.com/go-kratos/service-layout/api/helloworld/v1;v1";
option java_multiple_files = true;
option java_package = "dev.kratos.api.helloworld.v1";
option java_outer_classname = "HelloWorldProtoV1";// The greeting service definition.
service Greeter {// Sends a greetingrpc SayHello (HelloRequest) returns (HelloReply)  {option (google.api.http) = {// 定义一个 GET 接口,并且把 name 映射到 HelloRequestget: "/helloworld/{name}",// 可以添加附加接口additional_bindings {// 定义一个 POST 接口,并且把 body 映射到 HelloRequestpost: "/v1/greeter/say_hello",body: "*",}};}
}// The request message containing the user's name.
message HelloRequest {string name = 1;
}// The response message containing the greetings
message HelloReply {string message = 1;
}

这是一个使用 Protocol Buffer 版本 3 语法编写的文件。它定义了一个名为 “helloworld.v1” 的包,并导入了 “google/api/annotations.proto” 文件。

文件中还定义了一个服务 (service) “Greeter” ,它包含一个方法 (method) “SayHello” ,这个方法接收一个类型为 “HelloRequest” 的参数,并返回一个类型为 “HelloReply” 的响应。这个方法还使用了 “google.api.http” 注释来定义 HTTP 接口。具体地,它定义了一个 GET 接口,将路径中的 “name” 映射到 “HelloRequest”“name” 字段,并且还可以使用 POST 接口和附加绑定(additional bindings)。

“HelloRequest” 是一个请求消息,包含一个名为 “name” 的字符串字段。

“HelloReply” 是一个响应消息,包含一个名为 “message” 的字符串字段。

google/api/annotations.proto这个import是go-kratos就有的 可以直接从库里拷贝过来用
可以用Everything查询到直接拷贝过来用
尽量使用第三方引用,而不是引用线上的
拷贝下来的third_party可以将第三方源码放到里面 也可以放一些其他的 这是一种定义方式 可灵活运用

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

GoLand中如果需要protobuf插件识别到这是一个第三方引用就得设置protobuf的识别路径:
在这里插入图片描述

然后通过grpc插件生成go源码:

确定protobuf版本为最新版

cd到proto目录下

protoc --proto_path=../third_party --proto_path=. --go_out=. --go-grpc_out=. api.proto

--proto_path:protoc命令会查找所需要import的文件
--go_out:生成go的源码在哪
--go-grpc_out:生成go的grpc源码在哪
最后指明输入的是什么

其实 --go-grpc_out和一些其他的命令都是通过插件运行的 并不是protoc本身自带的,后面详解

注意: 不要把goland里proto插件和--proto_path对应起来 这是完全不一样的运行方式

2. protoc执行的插件加载原理是什么?

在使用 protoc 工具生成代码时,可以通过指定插件来生成不同类型的代码,例如生成 gRPC 相关的代码需要使用 grpc-go 插件。插件的加载是通过 protoc 的插件机制实现的,具体原理如下:

  1. protoc 工具会在执行时检查命令行参数中是否指定了插件。如果指定了插件,工具会将插件路径添加到环境变量 PATH 或者 PLUGIN_PATH 中。

  2. protoc 在执行时会扫描输入的 .proto 文件,并根据文件中定义的语法和语义信息生成一个中间表示,也就是 AST(抽象语法树)。

  3. protoc 会将生成的 AST 通过 proto 文件中指定的插件进行处理。这些插件实际上是由 protoc 调用的独立可执行文件,这些插件需要实现 protoc 的插件规范,并按照约定的方式接收和处理 AST 数据。

  4. 插件会将 AST 转换成目标语言的代码,并输出到指定的目录中。

  5. protoc 工具会根据插件生成的代码和用户指定的选项生成目标代码文件,例如 Go 语言中的 .go 文件。

protoc 执行过程 会从标注输入 读取到你的参数 回去查询 protoc-gen-{NAME} go_out 会去找 protoc-gen-go.exe

总之,插件机制可以使 protoc 工具灵活地扩展,以生成更多类型的代码或者执行更多的任务。插件必须按照 protoc 的插件规范实现,并且可以独立编写和发布。

3. proto文件中的package和go_package的作用

在 protobuf 中,package 和 go_package 是两个不同的概念,其作用分别如下:

  1. package:在 proto 文件中,package 是指定当前文件的命名空间,用于避免不同文件中的命名冲突。它的作用类似于 Go 语言中的 package 关键字。
    例如:一个 proto 文件的 package 声明为 example.foo,那么该文件中定义的所有消息、服务和枚举类型都将在命名空间 example.foo 下。

  2. go_package:go_package 是在 proto 文件中指定生成 Go 代码的包名和路径,它的作用是将生成的 Go 代码放在指定的包路径下。
    例如:如果一个 proto 文件中的 go_package 声明为 example.com/foo,那么生成的 Go 代码将会放在 example.com/foo 包下。

需要注意的是,go_package 的值应该是一个完整的包名,它包含了生成的代码的包路径和包名。通常情况下,go_package 的值应该和项目中的实际包路径保持一致,这样可以方便地导入和使用生成的代码。

在开发中,不建议发生冲突,应该使用合理的目录来避免这种错误

总之,package 和 go_package 在 proto 文件中都扮演了重要的角色,它们的正确使用可以使得生成的代码更加清晰易懂,并且方便代码的组织和维护。


三、protoc插件开发原理

开发 protoc 插件的原理如下:

  1. 插件是一个独立的可执行文件,它需要按照 protoc 的插件规范实现,这些规范包括:
    • 插件需要实现标准输入和标准输出,用于与 protoc 工具进行通信。
    • 插件需要读取 protoc 工具传递的输入 AST(抽象语法树),并将处理结果输出到标准输出中。
    • 插件需要指定插件的类型和插件的名字,可以在 proto 文件中通过 option 来指定。
  1. 插件开发者需要选择一种编程语言来实现插件。通常情况下,开发者可以选择自己熟悉的编程语言,例如 Go、Python、Java 等。但是,不同编程语言的实现方式会有所不同。

  2. 插件开发者需要了解 protoc 工具的使用方式和命令行参数,以及 proto 文件的语法和语义。在开发过程中,可以通过 protoc 工具和 -I 参数指定 proto 文件所在的路径。

  3. 开发者需要根据 proto 文件中定义的消息、服务和枚举类型,设计生成代码的逻辑和生成文件的格式。在生成代码时,需要遵循目标语言的规范和最佳实践,以生成高质量的代码。

总之,插件开发者需要了解插件规范和 protoc 工具的使用方式,以及目标语言的规范和最佳实践,以开发高效、可靠的插件,并生成高质量的代码。开发好的插件可以使得 protoc 工具更加灵活和强大,以适应不同的需求。

体验流程

官方示例:https://github.com/go-kratos/kratos/tree/main/cmd/protoc-gen-go-errors

作用:它可以在生成 Go 代码时,自动根据 proto 文件中的错误定义生成对应的错误类型。

目的是体验流程,调试,不是为了运行它

源码执行流程:

package mainimport ("flag""google.golang.org/protobuf/compiler/protogen""google.golang.org/protobuf/types/pluginpb"
)func main() {//接受输入的protoflag.Parse()var flags flag.FlagSetprotogen.Options{ParamFunc: flags.Set,}.Run(func(gen *protogen.Plugin) error {//运行之后gen会拿到proto文件 可以是多个gen.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)//它可以接受多个proto文件进行反射,反射功能它已经做好了//详细的struct可以自己点进去看//实际我们开发过程中,它帮我们生成代码,我们直接拿着用就行for _, f := range gen.Files {if !f.Generate {continue}//逻辑//generateFile(gen, f)}return nil})
}

它的大致原理是通过template.go模板语法,经过其他逻辑填充好,进行生成代码输出就行了
自己可以去template.go看一下,生成好的代码大致就是内样

官方只是做了说明,并没有说如何去调试它,如果用goland进行调试,得改源码

自己开发插件时执行过程是protoc来启动你的,并不是单独运行的,所以说你输入的 其实是protoc输入的 但是protoc是一个c文件,没办法去控制这个c文件进行调试

接着看执行逻辑,点进Run里后再点进run看源码:

func run(opts Options, f func(*Plugin) error) error {if len(os.Args) > 1 {return fmt.Errorf("unknown argument %q (this program should be run by protoc, not directly)", os.Args[1])}in, err := ioutil.ReadAll(os.Stdin)if err != nil {return err}req := &pluginpb.CodeGeneratorRequest{}if err := proto.Unmarshal(in, req); err != nil {return err}gen, err := opts.New(req)if err != nil {return err}if err := f(gen); err != nil {// Errors from the plugin function are reported by setting the// error field in the CodeGeneratorResponse.//// In contrast, errors that indicate a problem in protoc// itself (unparsable input, I/O errors, etc.) are reported// to stderr.gen.Error(err)}resp := gen.Response()out, err := proto.Marshal(resp)if err != nil {return err}if _, err := os.Stdout.Write(out); err != nil {return err}return nil
}

os.Stdin是标准输入流做的,是protoc提供的输入流,[]byte,不需要知道他是哪来的
然后通过Unmarshal进行反解成&pluginpb.CodeGeneratorRequest{}

那我们想要控制这个输入流,让他指定我们需要的这个输入流呢?

这就得改源码 修改这个输入流了 这块理解到这里就大差不差了

改源码逻辑后续我会更新


四、gin转发到grpc服务的原理和实现

1. 自己写.pb.go体验其原理

目的:proto映射成gin,把rpc的服务映射成http的服务

首先写一个rpc的服务,我想用gin集成进来,如何写, 然后再通过protoc来生成

效果:

  1. 直接开发rpc服务
  2. 我可以一键将rpc服务转换成http服务
  3. 有开发插件的能力,可以在插件里加一定的业务逻辑
  4. 这个插件一改,就会自动生成所需要的文件,更新迭代也很快,一个命令就可以

hello world级别的rpc服务:

项目目录:

  • api
    • api.proto
    • gin_grpc.pb.go
  • gin_grpc
    • app
      • app.go
    • server.go

api.proto:

syntax = "proto3";//这段后续再讲解
//go:generate protoc -I. --go_out=. --go-grpc_out=.  hello.protopackage template;import "google/api/annotations.proto";option go_package = "./;v1";// The greeting service definition.
service Greeter {// Sends a greetingrpc SayHello (HelloRequest) returns (HelloReply) {option(google.api.http) = {post:"/v1/sayhello"body:"*"};}// Sends another greetingrpc SayHelloAgain (HelloRequest) returns (HelloReply) {option(google.api.http) = {post:"/v1/sayhelloagain"body:"*"};}
}// The request message containing the user's name.
message HelloRequest {string name = 1;
}// The response message containing the greetings
message HelloReply {string message = 1;
}

生成grpc和模板所需文件
protoc -I. --go_out=. --go-grpc_out=. api.proto

gin_grpc.pb.go:

package v1import ("github.com/gin-gonic/gin""net/http"
)// 类似于grpc的写法 这个名称尽量和proto保持有关系
type Greeter struct {server GreeterServerrouter gin.IRouter
}// New进行外部调用 手动注册
func NewGreeterHttpServer(server GreeterServer, router gin.IRouter) *Greeter {return &Greeter{server: server, router: router}
}// 实例化这个过程 自动注册
func RegisterGreeterHttpServer(server GreeterServer, router gin.IRouter) {//我现在想用gin. Default,如果开发中我想使用其他的方式实例化gin 把权力交给外部g := &Greeter{server: server, router: router}g.RegisterService()
}// 然后"生成"这个SayHello 这个_0是为了防止冲突
func (g *Greeter) SayHello_0(c *gin.Context) {//入参定义var in HelloRequest//入参if err := c.BindJSON(&in); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}//调用生成grpc的方法   尽量松耦合//在struct定义这个接口保持松耦合  这样就能通过SayHello转一次out, err := g.server.SayHello(c, &in)if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}c.JSON(http.StatusOK, out)
}// 注入路径当中
func (g *Greeter) RegisterService() {//路由映射g.router.Handle("POST", "/v1/greeter/register", g.SayHello_0)
}

server.go:

package gin_grpcimport ("context""fmt"hpb "NewGo/api"
)type helloServer struct {hpb.UnimplementedGreeterServer
}func NewHelloServer() *helloServer {return &helloServer{}
}func (h *helloServer) SayHello(ctx context.Context, request *hpb.HelloRequest) (*hpb.HelloReply, error) {return &hpb.HelloReply{Message: fmt.Sprintf("Hello %s", request.Name),}, nil
}func (h *helloServer) SayHelloAgain(ctx context.Context, request *hpb.HelloRequest) (*hpb.HelloReply, error) {return &hpb.HelloReply{Message: fmt.Sprintf("Hello %s again", request.Name),}, nil
}
//注册到grpc中   这段代码没啥说的
var _ hpb.GreeterServer = &helloServer{}

app.go:

package mainimport (hpb "NewGo/api""NewGo/gin_grpc""github.com/gin-gonic/gin""net/http"
)func main() {helloSrv := gin_grpc.NewHelloServer()engine := gin.Default()//把注册函数和gin绑定起来hpb.RegisterGreeterHttpServer(helloSrv, engine)//http服务   使用gin启动也行   ,尽量把gin 扔到http里做 主要是优雅退出会方便一点server := &http.Server{Addr:    ":8082",Handler: engine,}//支持自动生成端口以及自定义ip和端口_ = engine.SetTrustedProxies(nil)//启动   可严谨判断if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {panic(err)}
}

启动后访问一下:

整个项目中只有.pb.go是自动生成的 我们是为了体验才自己写的 还有一个好处,就是可以自动生成Swagger文档,这样就不需要自己写api文档了

注意是post加json发送
在这里插入图片描述
这样就理解了rpc转http的执行原理是什么了
为后续开发自定义插件做铺垫

2. 细节纠错

  • 文件命名的规范:应该是由开发者决定的,自己去写死这个 也没问题,自己决定比较好点
  • proto中自动注册所需要的import:安装"google.golang.org/genproto/googleapis/api/annotations"即可 不要冲突注册过程 尽量别破坏插件中原有的逻辑

五、go的template实现动态生成代码

学习template语法文章:https://colobu.com/2019/11/05/Golang-Templates-Cheatsheet/#Range

学过django或者flask里Jinjia2模板会入门很快的

proto里importpackagego_package不需要自己填充 proto gen会帮我们做这些

重点是把service填充好

示例:

package mainimport ("bytes""fmt""html/template""strings"
)var tpl = `
type {{$.Name}}HTTPServer struct {server {{$.Name}}Serverrouter gin.IRouter
}// 实例化这个过程 自动注册
func Register{{$.Name}}HttpServer(server {{$.Name}}Server, router gin.IRouter) {//我现在想用gin. Default,如果开发中我想使用其他的方式实例化gin 把权力交给外部g := &{{$.Name}}HTTPServer{server: server, router: router}g.RegisterService()
}
{{ range .Methods }}
// 然后"生成"这个SayHello 这个_0是为了防止冲突
func (g *{{$.Name}}HTTPServer) {{ .HandlerName }}(c *gin.Context) {//入参定义var in {{ .Request }}//入参if err := c.BindJSON(&in); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}//调用生成grpc的方法   尽量松耦合//在struct定义这个接口保持松耦合  这样就能通过SayHello转一次out, err := g.server.{{ .Name }}(c, &in)if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}c.JSON(http.StatusOK, out)
}
{{ end }}
// 注入路径当中
func (g *{{$.Name}}HTTPServer) RegisterService() {//路由映射
{{ range .Methods }}g.router.Handle("{{ .Method }}", "{{ .Path }}", g.{{ .HandlerName }})
{{ end }}
}`type serviceDesc struct {Name    stringMethods []method
}
type method struct {Name    stringRequest stringReply   string//http rulePath   stringMethod string //指的是post还是get等Body   string
}func (m *method) HandlerName() string {return m.Name + "_0"
}
func main() {//模板//缓冲区buf := new(bytes.Buffer)tmpl, err := template.New("http").Parse(strings.TrimSpace(tpl))if err != nil {panic(err)}//模仿s := serviceDesc{Name: "Greeter",Methods: []method{{Name:    "SayHello",Request: "HelloRequest",Reply:   "HelloReply",Path:    "/v1/sayhello",Method:  "POST",Body:    "*",},},}//把内容输出到buf里面err = tmpl.Execute(buf, s)if err != nil {return}fmt.Println(buf.String())
}

六、protoc生成gin的插件

插件:
链接:https://pan.baidu.com/s/1pEJ8xxo81FGJJoV2rQ2Y6A?pwd=1234
提取码:1234

通过大量的前置工作 这里面插件的代码应该能看懂
注释写的很清楚直接go build就可以 没问题的

示例:

目录结构:

  • tools
    • generator(下载的插件)
    • google(third_party里的google文件夹)
    • api.proto
    • main.go

api.proto:

syntax = "proto3";//go:generate protoc -I. --go_out=. --go-grpc_out=.  hello.protopackage template;import "google/api/annotations.proto";option go_package="./;v1";// The greeting service definition.
service Greeter {// Sends a greetingrpc SayHello (HelloRequest) returns (HelloReply) {option (google.api.http) = {post: "/v1/sayhello"body: "*"};}// Sends another greetingrpc SayHelloAgain (HelloRequest) returns (HelloReply) {option (google.api.http) = {post: "/v1/sayhelloagain"body: "*"};}
}// The request message containing the user's name.
message HelloRequest {string name = 1;
}// The response message containing the greetings
message HelloReply {string message = 1;
}

main.go:

package mainimport ("flag""google.golang.org/protobuf/compiler/protogen""google.golang.org/protobuf/types/pluginpb""NewGo/tools/generator"
)func main() {flag.Parse()var flags flag.FlagSetprotogen.Options{ParamFunc: flags.Set,}.Run(func(gen *protogen.Plugin) error {gen.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)for _, f := range gen.Files {if !f.Generate {continue}generator.GenerateFile(gen, f)}return nil})
}

说明一下: 如果想在main里调试的话 到generator里的generator.go文件把这段注释打开
如果是用protoc生成的话把这段注释加上

func GenerateFile(gen *protogen.Plugin, file *protogen.File) *protogen.GeneratedFile {if len(file.Services) == 0 {return nil}//设置生成的文件名,文件名会被protoc使用,生成的文件会被放在相应的目录下filename := file.GeneratedFilenamePrefix + "_gin.pb.go"g := gen.NewGeneratedFile(filename, file.GoImportPath)//该注释会被go的ide识别到, 表示该文件是自动生成的,尽量不要修改g.P("// Code generated by protoc-gen-gin. DO NOT EDIT.")g.P()//会提取到proto中option go_package 然后写入g.P("package ", file.GoPackageName)//该函数是注册全局的packge 的内容,但是此时不会写入//g.Content()之后才能看到真正写入的内容 注册即可g.QualifiedGoIdent(ginPkg.Ident(""))g.QualifiedGoIdent(httpPkg.Ident(""))for _, service := range file.Services {genService(file, g, service)}//自己写文件看结果//f, err := os.Create("api_gin.pb.go")////if err != nil {//	//log.Fatal(err)//}////defer f.Close()////contentStr, _ := g.Content()//_, _ = f.WriteString(string(contentStr))return g
}

然后直接到tools目录里运行go build
把生成后的exe文件重命名为protoc-gen-gin.exe
放到go目录下的bin文件夹:

在这里插入图片描述
这时候使用protoc命令就可以使用这个插件对proto进行生成gin源码了

示例:

api.proto:

syntax = "proto3";//go:generate protoc -I. --go_out=. --go-grpc_out=.  hello.protopackage template;import "google/api/annotations.proto";option go_package = "./;v1";// The greeting service definition.
service Greeter {// Sends a greetingrpc SayHello (HelloRequest) returns (HelloReply) {option(google.api.http) = {post:"/v1/sayhello"body:"*"};}// Sends another greetingrpc SayHelloAgain (HelloRequest) returns (HelloReply) {option(google.api.http) = {post:"/v1/sayhelloagain"body:"*"};}
}// The request message containing the user's name.
message HelloRequest {string name = 1;
}// The response message containing the greetings
message HelloReply {string message = 1;
}

打开终端进入这个目录运行:

protoc --proto_path=. --proto_path=../third_party --go_out=. --go-grpc_out=. --gin_out=. api.proto
使用了--proto_path就不需要-I.了   自己指明比较好

这里使用到的--proto_path=../third_party是因为proto文件里指明的第三方文件 不是插件里指明的
在这里插入图片描述

然后写一个服务端:server.go和启动文件:app.go进行测试

server.go:

package gin_grpcimport ("context""fmt"hpb "NewGo/api"
)type helloServer struct {hpb.UnimplementedGreeterServer
}func NewHelloServer() *helloServer {return &helloServer{}
}func (h *helloServer) SayHello(ctx context.Context, request *hpb.HelloRequest) (*hpb.HelloReply, error) {return &hpb.HelloReply{Message: fmt.Sprintf("Hello %s", request.Name),}, nil
}func (h *helloServer) SayHelloAgain(ctx context.Context, request *hpb.HelloRequest) (*hpb.HelloReply, error) {return &hpb.HelloReply{Message: fmt.Sprintf("Hello %s again", request.Name),}, nil
}var _ hpb.GreeterServer = &helloServer{}

app.go:

package mainimport (hpb "NewGo/api""NewGo/gin_grpc""github.com/gin-gonic/gin""net/http"
)func main() {helloSrv := gin_grpc.NewHelloServer()engine := gin.Default()//把注册函数和gin绑定起来hpb.RegisterGreeterServerHTTPServer(helloSrv, engine)//http服务   使用gin启动也行   ,尽量把gin 扔到http里做 主要是优雅退出会方便一点server := &http.Server{Addr:    ":8082",Handler: engine,}//支持自动生成端口以及自定义ip和端口_ = engine.SetTrustedProxies(nil)//启动   可严谨判断if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {panic(err)}
}

直接运行app.go
进行post访问:
加json进行请求

在这里插入图片描述

在这里插入图片描述

插件是完全自定义的,如果公司有一套标准的话可以嵌入到插件里自动生成 就不用每次进行手动写了,公司应该都有一套标准,自己写很麻烦,尽量用模板进行生成,还可以加入【链路追踪】【熔断降级、限流】等功能。
我连实习都没开始,我是废物其他无权评价

相关文章:

【protoc自定义插件】「go语言」实现rpc的服务映射成http的服务,protoc生成gin的插件,(详解实现原理及过程)

文章目录前言一、工程实践中如何更好的使用proto文件?二、protoc命令如何查询依赖的proto文件以及执行原理1. protoc命令如何查询依赖的proto文件2. protoc执行的插件加载原理是什么?3. proto文件中的package和go_package的作用三、protoc插件开发原理体…...

【C语言】3天速刷C语言(语句、函数)

语句分支语句if语句if语句语法结构语法结构: if(表达式)语句; if(表达式)语句1; else语句2; //多分支 if(表达式1)语句1; else if(表达式2)语句2; else语句3;表达式如果成立,则执行,不成立则弹出。switch语句语法结构:switch(…...

Linux系统中指针的详细分析与操作

文章目录 一、指针 二、指针的初始化 三、指针的运算 四、指针与数组 五、指针与字符串 六、函数指针 七、NULL 指针 八、对复杂指针的解释 C 语言指针真正精髓的地方在于指针可以进行加减法,这一点极大的提升了程序的对指针使用的灵活性,同时也…...

工程(十一)——NUC11+D435i+VINS-FUSION+ESDF建图(github代码)

博主的合并代码gitgithub.com:huashu996/VINS-FUSION-ESDFmap.git一、D435i深度相机配置1.1 SDKROS参考我之前的博客,步骤和所遇见的问题已经写的很详细了https://blog.csdn.net/HUASHUDEYANJING/article/details/129323834?spm1001.2014.3001.55011.2 相机标定参数…...

第十四届蓝桥杯三月真题刷题训练——第 4 天

目录 题目 1 :九数算式_dfs回溯(全排列) 题目描述 运行限制 代码: 题目2:完全平方数 问题描述 输入格式 输出格式 样例输入 1 样例输出 1 样例输入 2 样例输出 2 评测用例规模与约定 运行限制 代码: 题目 1 &am…...

Hadoop 运行环境搭建(开发重点)

文章目录Hadoop 运行环境搭建(开发重点)一、安装JDK二、安装配置 Hadoop1、安装 hadoop2、hadoop 目录结构3、设置免密登录4、完全分布式模式(开发重点)1)分发jdk2)集群配置(1) 集群部署规划(2) 配置文件说…...

在社交媒体上行之有效的个人IP趋势

如果您认为无论是获得一份工作、建立一家企业还是推动个人职业发展,社交媒体都是帮助您实现目标的可靠工具,那么个人IP就是推动这一工具前进的燃料。个人IP反映了您是谁,您在所处领域的专业程度,以及您与他人的区别。社交媒体将有…...

Java网络编程

网络编程 什么是网络编程? 可以让设备中的程序与网络上其他设备中的程序进行数据交互(实现网络通信) Java.net. 包下提供了网络编程的解决方案* 基本的通信架构 基本的通信架构有两种方式:CS架构(Client客户端/Se…...

PTA:L1-001 Hello World、L1-002 打印沙漏、L1-003 个位数统计(C++)

目录 L1-001 Hello World 问题描述: 实现代码: L1-002 打印沙漏 问题描述: 实现代码: 原理思路: L1-003 个位数统计 题目描述: 实现代码: 原理思路: 过于简单的就不再写题…...

构造HTTP请求

使用formform使用如下:<body><!-- 表单标签,允许用户和服务器之间交互数据 --><form action"https://www.sogou.com" method"get"><!-- 要求提交的数据以键值对的结构来组织 --><input type"text" name"stduent…...

转速/线速度/角速度计算FC

工业应用中很多设备控制离不开转速、线速度的计算,这篇博客给大家汇总整理。张力控制的开环闭环方法中也离不开转速和线速度的计算,详细内容请参看下面的文章链接: PLC张力控制(开环闭环算法分析)_plc的收卷张力控制系统_RXXW_Dor的博客-CSDN博客里工业控制张力控制无处不…...

学习笔记:Java并发编程(补)ThreadLocal

【尚硅谷】学习视频&#xff1a;https://www.bilibili.com/video/BV1ar4y1x727【黑马程序员】学习视频&#xff1a;https://www.bilibili.com/video/BV15b4y117RJ 参考书籍 《实战 JAVA 高并发程序设计》 葛一鸣 著《深入理解 JAVA 虚拟机 | JVM 高级特性与最佳实践》 周志明 著…...

HashMap底层实现原理及面试题

文章目录1. 常见的数据结构有三种结构1.1 各自数据结构的特点2. HashMap2.1 概述2.2 底层结构2.2.1 HashMa实现原理&#xff1a;2.2.1.1 map.put(k,v)实现原理2.2.1.2 map.get(k)实现原理2.2.1.3 resize源码2.2.2 HashMap常用的变量2.2.3 HashMap构造函数2.3 JDK1.8之前存在的问…...

【STM32】进阶(二):DMA+ADC实现模拟量检测

1、简述 DMA&#xff1a;Direct Memory Access&#xff0c;直接内存访问 ADC&#xff1a;Analog to Digital Converter&#xff0c;模数转换器&#xff0c;模拟信号转换成数字信号的电路&#xff08;采样-量化-编码&#xff09; 参考博客&#xff1a; STM32DMA功能详解 STM32…...

Lab2_Simple Shell_2020

Lab2: 实验目的&#xff1a;给xv6添加新的系统调用 并理解系统调用是如何工作的&#xff0c;并理解xv6内核的一些内部特征 实验准备&#xff1a; 阅读xv6的第2章以及第4章的4.3,4.3小节熟悉下面的源码 用户态相关的代码&#xff1a;user/user.h和user/usys.pl内核态相关的代…...

2023最全电商API接口 高并发请求 实时数据 支持定制 电商数据 买家卖家数据

电商日常运营很容易理解&#xff0c;就是店铺商品维护&#xff0c;上下架&#xff0c;评价维护&#xff0c;库存数量&#xff0c;协助美工完成制作详情页。店铺DSR&#xff0c;好评率&#xff0c;提升客服服务等等&#xff0c;这些基础而且每天都必须做循环做的工作。借助电商A…...

MySQL 的索引类型

1. 按照功能划分 按照功能来划分&#xff0c;索引主要有四种&#xff1a; 普通索引唯一性索引主键索引全文索引 普通索引就是最最基础的索引&#xff0c;这种索引没有任何的约束作用&#xff0c;它存在的主要意义就是提高查询效率。 普通索引创建方式如下&#xff1a; CREATE…...

< Linux > 进程信号

目录 1、信号入门 生活角度的信号 技术应用角度的信号 前台进程 && 后台进程 信号概念 用kill -l命令察看系统定义的信号列表 信号处理的方式 2、信号产生前 用户层产生信号的方式 3、产生信号 3.1、通过终端按键产生信号 3.2、核心转储core dump 3.3、调用系统函数…...

Pyspark基础入门7_RDD的内核调度

Pyspark 注&#xff1a;大家觉得博客好的话&#xff0c;别忘了点赞收藏呀&#xff0c;本人每周都会更新关于人工智能和大数据相关的内容&#xff0c;内容多为原创&#xff0c;Python Java Scala SQL 代码&#xff0c;CV NLP 推荐系统等&#xff0c;Spark Flink Kafka Hbase Hi…...

C/C++每日一练(20230307)

目录 1. 国名排序 ★★ 2. 重复的DNA序列 ★★★ 3. 买卖股票的最佳时机 III ★★★ &#x1f31f; 每日一练刷题专栏 C/C 每日一练 ​专栏 Python 每日一练 ​专栏 1. 国名排序 小李在准备明天的广交会&#xff0c;明天有来自世界各国的客房跟他们谈生意&#xff0c…...

一条SQL查询语句是如何执行的?

平时我们使用数据库&#xff0c;看到的通常都是一个整体。比如&#xff0c;你有个最简单的表&#xff0c;表里只有一个ID字段&#xff0c;在执行下面这个查询语句时&#xff1a; mysql> select * from T where ID10&#xff1b; 我们看到的只是输入一条语句&#xff0c;返…...

tcsh常用配置

查看当前的shell类型 在 Linux 的世界中&#xff0c;有着许多 shell 程序。常见的有&#xff1a; Bourne shell (sh) C shell (csh) TC shell (tcsh) Korn shell (ksh) Bourne Again shell (bash) 其中&#xff0c;最常用的就是bash和tcsh&#xff0c;本次文章介绍tcsh的…...

YOLOv5源码逐行超详细注释与解读(2)——推理部分detect.py

前言 前面简单介绍了YOLOv5的项目目录结构&#xff08;直通车&#xff1a;YOLOv5源码逐行超详细注释与解读&#xff08;1&#xff09;——项目目录结构解析&#xff09;&#xff0c;对项目整体有了大致了解。 今天要学习的是detect.py。通常这个文件是用来预测一张图片或者一…...

什么叫个非对称加密?中间人攻击?数字签名?

非对称加密也称为公钥密码。就是用公钥来进行加密&#xff0c;撒子意思&#xff1f; 非对称加密 在对称加密中&#xff0c;我们只需要一个密钥&#xff0c;通信双方同时持有。而非对称加密需要4个密钥&#xff0c;来完成完整的双方通信。通信双方各自准备一对公钥和私钥。其中…...

2023.03.07 小记与展望

碎碎念系列全新改版&#xff01; 以后就叫小记和展望系列 最近事情比较多&#xff0c;写篇博客梳理一下自己3月到5月下旬的一个规划 一、关于毕设 毕设马上开题答辩了&#xff0c;准备再重新修改一下开题报告&#xff0c;梳理各阶段目标。 毕设是在去年的大学生创新训练项目…...

MyBatis源码分析(七)MyBatis与Spring的整合原理与源码分析

文章目录写在前面一、SqlSessionFactoryBean配置SqlSessionFactory1、初识SqlSessionFactoryBean2、实现ApplicationListener3、实现InitializingBean接口4、实现FactoryBean接口5、构建SqlSessionFactory二、SqlSessionTemplate1、初始SqlSessionTemplate2、SqlSessionTemplat…...

基于声网 Flutter SDK 实现多人视频通话

前言 本文是由声网社区的开发者“小猿”撰写的Flutter基础教程系列中的第一篇。本文除了讲述实现多人视频通话的过程&#xff0c;还有一些 Flutter 开发方面的知识点。该系列将基于声网 Fluttter SDK 实现视频通话、互动直播&#xff0c;并尝试虚拟背景等更多功能的实现。 如果…...

IT服务管理(ITSM) 中的大数据

当我们谈论IT服务管理&#xff08;ITSM&#xff09;领域的大数据时&#xff0c;我们谈论的是关于两件不同的事情&#xff1a; IT 为业务提供的大数据工具/服务 - 对业务运营数据进行数字处理。IT 运营中的大数据 – 处理和利用复杂的 IT 运营数据。 面向业务运营的大数据服务…...

Validator校验之ValidatorUtils

注意&#xff1a;hibernate-validator 与 持久层框架 hibernate 没有什么关系&#xff0c;hibernate-validator 是 hibernate 组织下的一个开源项目 。 hibernate-validator 是 JSR 380&#xff08;Bean Validation 2.0&#xff09;、JSR 303&#xff08;Bean Validation 1.0&…...

C++---背包模型---采药(每日一道算法2023.3.7)

注意事项&#xff1a; 本题是"动态规划—01背包"的扩展题&#xff0c;dp和优化思路不多赘述。 题目&#xff1a; 辰辰是个天资聪颖的孩子&#xff0c;他的梦想是成为世界上最伟大的医师。 为此&#xff0c;他想拜附近最有威望的医师为师。 医师为了判断他的资质&…...