• Go使用protocolbuffer快速开发api服务教程


    如果无法查看图片, 请跳转博客正文: https://www.cnblogs.com/zolo/p/14066444.html

    前述

    本教程只说"实践",不谈"理论". 如果哪位觉得有趣, 可以加本人QQ(1255422783)详细交流!

    问题

    对于后端开发, 经常"众口难调". 一套业务逻辑却要三套不同实现API!

    • 网页端要"http(json) api"(如restful api)
    • 移动端要"websocket api"
    • 服务端要"grpc api"

    正题

    本教程主要介绍如何使用"protogen + protoapi"的开发步骤.
    源码仓库:https://github.com/fasgo/demo

    开发步骤

    第1步: Goland启用"GoModule"支持

    Settings > Go > Go Modules > 打勾 Enable go modules intergration

    image

    第2步: 根据需求定义proto

    syntax = "proto3";
    
    package api;
    
    // 学生数据结构
    message Student {
      uint64 sno = 1;   // 学生编号
      string name = 2;  // 学生名称
      uint32 age = 3;   // 学生年龄
      bool   male = 4;  // 性别为男
      string desc = 5;  // 学生介绍
    }
    
    // 搜索请求
    message AllReq {
      int32 from = 1; // 分页开始下标(从0开始)
      int32 size = 2; // 分页大小
      string search = 3; // 模糊查询的输入内容
      string field = 4; // 查询结果排序字段
      bool desc = 5; // 查询结果排序是否DESC
    }
    
    // 搜索响应
    message AllRsp{
      int32  total = 1; //查询结果总数
      repeated Student data = 2; // 查询结果数据
    }
    
    // 所有方法都支持+JSON与+FORM,根据需求灵活配置
    // 1. +JSON(Content-Type:application/json)
    // 2. +FORM(Content-Type:application/x-www-form-urlencode或multipart/form-data)
    service StudentService {
      // +POST /demo/students
      rpc Add(Student) returns (Student);
      // +DELETE /demo/students/:sno
      rpc Del(Student) returns (Student);
      // +PUT /demo/students/:sno
      rpc Upd(Student) returns (Student);
      // +WBSK /demo/student/ws
      // +GET /demo/students/:sno
      rpc Get(Student) returns (Student);
      // +GET /demo/students
      rpc All(AllReq) returns (AllRsp);
    }
    
    

    第3步: 进入项目执行protogen

    项目结构:

    E:	emp
    |__api
    |__biz
    |__test-client
    |__conf.toml
    |__go.mod
    |__go.sum
    |__main.go
    |__README.md
    

    进入项目目录执行protogen, 首次执行会下载相关的插件, 过程稍慢, 请耐心稍等!

    E:	emp>protogen
    2020-12-01 11:43:18 [I] - fetch https://maven.aliyun.com/repository/central/com/google/protobuf/protoc/3.14.0/protoc-3.14.0-windows-x86_64.exe
    2020-12-01 11:43:23 [I] - goget google.golang.org/protobuf/cmd/protoc-gen-go@v1.25.0
    go: downloading google.golang.org/protobuf v1.25.0
    go: found google.golang.org/protobuf/cmd/protoc-gen-go in google.golang.org/protobuf v1.25.0
    2020-12-01 11:43:38 [I] - goget google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.0.1
    go: downloading google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.1
    go: downloading google.golang.org/grpc v1.33.2
    go: downloading google.golang.org/protobuf v1.25.0
    2020-12-01 11:44:02 [I] - goget github.com/fasgo/protoapi/cmd/protoc-gen-go-http@v1.25.0-0.1.1
    go: downloading github.com/fasgo/protoapi/cmd/protoc-gen-go-http v1.25.0-0.1.1
    go: downloading github.com/fasgo/protoapi v0.0.2
    go: downloading google.golang.org/protobuf v1.25.0
    2020-12-01 11:44:18 [I] - build E:	empapistudent.proto
    

    执行protogen后, 会在proto文档所在目录生成:

    • xxx.pb.go: 使用protoc-gen-go生成的PB源码
    • xxx_grpc.pb.go: 使用protoc-gen-go-grpc生成的GRPC源码
    • xxx_http.pb.go: 使用protoc-gen-go-http生成的http适配代码, 后面的http实现就靠它了!!!

    注意: 如果你用Goland,可以打开Terminal控制台操作会更方便:
    image

    第4步: 复制service模板

    import (
    	"context"
    )
    type StudentServiceService struct {
    	*api.UnimplementedStudentServiceServer
    }
    var _ api.StudentServiceServer = (*StudentServiceService)(nil)
    func (s *StudentServiceService) Add(ctx context.Context, req *api.Student) (rsp *api.Student, err error) {
    	return
    }
    func (s *StudentServiceService) Del(ctx context.Context, req *api.Student) (rsp *api.Student, err error) {
    	return
    }
    func (s *StudentServiceService) Upd(ctx context.Context, req *api.Student) (rsp *api.Student, err error) {
    	return
    }
    func (s *StudentServiceService) Get(ctx context.Context, req *api.Student) (rsp *api.Student, err error) {
    	return
    }
    func (s *StudentServiceService) All(ctx context.Context, req *api.AllReq) (rsp *api.AllRsp, err error) {
    	return
    }
    

    注意:
    为每个proto文件生成的在xxxx_http.pb.go(例如stduent_http.pb.go)的最后会有service的实现模板!
    开发人员直接将其复制到自己的biz代码即可, 这样可以大大提高开发效率!

    第5步: 实现service逻辑

    package biz
    
    import (
    	"context"
    	"fmt"
    	"github.com/fasgo/base"
    	"github.com/fasgo/demo/api"
    )
    
    type StudentServiceService struct {
    	*api.UnimplementedStudentServiceServer
    }
    
    var _ api.StudentServiceServer = (*StudentServiceService)(nil)
    
    func (s *StudentServiceService) Add(ctx context.Context, req *api.Student) (rsp *api.Student, err error) {
    	fmt.Println(base.Json(req))
    	rsp = req
    	return
    }
    func (s *StudentServiceService) Del(ctx context.Context, req *api.Student) (rsp *api.Student, err error) {
    	fmt.Println(base.Json(req))
    	rsp = req
    	return
    }
    func (s *StudentServiceService) Upd(ctx context.Context, req *api.Student) (rsp *api.Student, err error) {
    	fmt.Println(base.Json(req))
    	rsp = req
    	return
    }
    func (s *StudentServiceService) Get(ctx context.Context, req *api.Student) (rsp *api.Student, err error) {
    	fmt.Println(base.Json(req))
    	rsp = req
    	return
    }
    func (s *StudentServiceService) All(ctx context.Context, req *api.AllReq) (rsp *api.AllRsp, err error) {
    	fmt.Println(base.Json(req))
    	rsp = new(api.AllRsp)
    	return
    }
    
    

    第6步: 注册service实例, 并启动服务

    package main
    
    import (
    	"github.com/fasgo/demo/api"
    	"github.com/fasgo/demo/biz"
    	"github.com/fasgo/protoapi"
    )
    
    func main() {
    	// 1. 创建server. 可以从conf配置, 也可以编程配置
    	//s := serverWithConfig()
    	s := serverWithConfToml()
    
    	// 2. 注册服务实现. 每个service会有对应的Registry/Implement注册到server
    	s.RegisterService(api.StudentServiceRegistry, new(biz.StudentServiceService))
    
    	// 3. 监听与服务
    	if err := s.ListenAndServe(); err != nil {
    		panic(err)
    	}
    }
    
    // 从conf.toml加载配置
    func serverWithConfToml() *protoapi.Server {
    	// load config from conf.toml
    	s := protoapi.NewServer()
    	return s
    }
    
    // 自己定义配置
    func serverWithConfig() *protoapi.Server {
    	c := &protoapi.Config{
    		HttpAddr:        ":80",
    		GrpcAddr:        ":90",
    		WbskCheckOrigin: -1,
    	}
    	s := protoapi.NewServerWith(c)
    	return s
    }
    
    

    第7步: 客户端连接测试

    • grpc client
    package main
    
    import (
    	"context"
    	"fmt"
    	"github.com/fasgo/demo/api"
    	"google.golang.org/grpc"
    )
    
    func main() {
    	conn, err := grpc.Dial("127.0.0.1:90", grpc.WithInsecure(), grpc.WithBlock())
    	if err != nil {
    		panic(err)
    	}
    	defer conn.Close()
    
    	client := api.NewStudentServiceClient(conn)
    
    	req := &api.Student{
    		Name: "小王",
    	}
    
    	rsp, err := client.Add(context.Background(), req)
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Printf("%+v
    ", rsp)
    }
    
    /*
    输出:
    Load conf success: E:	empconf.toml
    name:"小王"
    */
    
    
    • http client
    package main
    
    import (
    	"bytes"
    	"encoding/json"
    	"fmt"
    	"github.com/fasgo/demo/api"
    	"io"
    	"net/http"
    	"os"
    )
    
    func main() {
    	tag := &api.Student{
    		Name: "demo",
    	}
    	bs, _ := json.Marshal(tag)
    	rsp, err := http.Post("http://127.0.0.1/demo/students", "application/json", bytes.NewReader(bs))
    	if err != nil {
    		panic(err)
    	}
    	defer rsp.Body.Close()
    
    	fmt.Println(rsp.Proto, rsp.Status)
    	io.Copy(os.Stdout, rsp.Body)
    }
    
    /*
    输出:
    Load conf success: E:	empconf.toml
    HTTP/1.1 200 OK
    {"code":0,"data":{"name":"demo"},"tag":"StudentService.Add"}
    */
    
    • websocket client

    这里使用chrome的smart websocket client:
    image

    搭建环境

    第1步: 下载安装Go 1.15

    GO下载页面: https://golang.google.cn/dl/

    详情不再赘述! Go都不会安装, 哪还能说啥?

    第2步: 下载安装protogen

    • protogen介绍

      protogen是作者开发的一个快速构建工具,封装了protoc等一系列pb常用工具的下载,安装与使用! 一键完成proto的所有烦琐配置!

    • protogen安装:

      "强烈建议添加protogen到系统环境PATH!"

      第3步教程假定你已经将protogen添加到PATH.

      protogen采用go get安装方式, 整体流程分4步:

      1. 指定GoPath
      2. 启用GoModule
      3. 设置GoProxy
      4. GoGet下载安装

      具体脚本操作:

      • windows安装: (以临时目录为例)
      set GOPATH=c:WindowsTemp
      set GO111MODULE=on
      set GOPROXY=https://goproxy.cn
      go get github.com/fasgo/protogen@latest
      

      安装位置: c:WindowsTempinprotogen

       c:WindowsTempinprotogen.exe --help
       Usage of protogen [options] {files...} :
         -clean
               清除缓存.protogen
         -compatible
               gRPC接口兼容v1.x
         -debug
               开启调试
         -goproxy string
               GO代理服务,默认$GOPROXY(https://goproxy.cn) (default "https://goproxy.cn")
         -h    打印帮助
         -help
               打印帮助
         -proto_path string
               PB查找路径,多值逗号分隔
         -version
               打印版本
      
      • linux(darwin)安装: (以临时目录为例)
      export GOPATH=/tmp
      export GO111MODULE=on
      export GOPROXY=https://goproxy.cn
      go get github.com/fasgo/protogen@latest
      

      安装位置: /tmp/bin/protogen

      /tmp/bin/protogen --help
      Usage of protogen [options] {files...} :
        -clean
              清除缓存.protogen
        -compatible
              gRPC接口兼容v1.x
        -debug
              开启调试
        -goproxy string
              GO代理服务,默认$GOPROXY(https://goproxy.cn) (default "https://goproxy.cn")
        -h    打印帮助
        -help
              打印帮助
        -proto_path string
              PB查找路径,多值逗号分隔
        -version
              打印版本
      

    第3步: 下载项目源码

    git clone https://github.com/fasgo/demo.git e:	emp
    

    step-by-step教程:Go使用protocolbuffer快速构建api服务教程

  • 相关阅读:
    MS CRM 2011 Field Security Profile
    MS CRM 2011 在CRM中使用REST Endpoint
    如何在报表的Header和Footer中使用DataSet中的Field
    MS CRM 2011 如何获得Option Set的Label与Value
    MS CRM 2011 如何获得当前用户使用的界面语言
    MS CRM 2011 如何创建基于SQL的自定义报表,并使用数据预筛选(PreFiltering)
    MS CRM 2011 与 SharePoint 2010 的集成
    查看服务器的连接数
    ie6,ie7,ie8,ie9 css bug兼容解决记录
    【转】命令行查看Memcached运行状态
  • 原文地址:https://www.cnblogs.com/zolo/p/14066444.html
Copyright © 2020-2023  润新知