《go微服务框架Kratos 》连载五:使用protbuf创建http服务器

bitnavigator
• 阅读 1694

一、介绍

前几张我们已经学了kratos的基本框架。本章我们来深入剖析一下原理。
kratos框架之所以能够使用protbuf创建http服务器,多亏了框架自带的
protoc-gen-go-http插件。
那么我们是否可以在其他地方使用这个插件呢,答案是可以,今天我们就试一下。
本文章代码地址在 https://github.com/hisheng/kratos-http

1.1 准备目录

我们新建一个 kratos-http目录,并且go模块初始化。
创建目录:

mkdir kratos-http && cd kratos-http

go项目初始化:
我们在kratos-http根目录执行一下代码

go mod init github.com/hisheng/kratos-http

1.2 安装protoc-gen-go以及http扩展protoc-gen-go-http

我们在kratos-http根目录执行一下代码,安装扩展。

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2@latest

二、创建protobuf文件

2.1 准备目录

我们在kratos-http根目录,创建一个api目录来存放我们的proto文件

mkdir api && cd api

2.2 创建user.proto

此时我们新建一个 user.proto 文件用来实现我们的http服务。

touch user.proto

我们user.proto的代码如下:

syntax = "proto3";
package api;
import "google/api/annotations.proto";

option go_package = "github/hisheng/kratos-http/api";

service User {
  rpc CreateUser (CreateUserRequest) returns (CreateUserReply){
    option (google.api.http) = {
      post: "/user",
      body: "*",
    };
  };
  rpc ListUser (ListUserRequest) returns (ListUserReply){
    option (google.api.http) = {
      get: "/users",
    };
  };
}
message CreateUserRequest {}
message CreateUserReply {}
message ListUserRequest {}
message ListUserReply {}

2.3 解决proto文件 cannot import "google/api/annotations.proto"

此时我们在proto文件里,引入了一个第三方的proto文件,此文件没有报错怎么办?
我们一般这类的第三方文件依赖发到third_party目录。

2.3.1 引入google proto库。

打开https://github.com/hisheng/kratos-http我们项目代码地址。
直接把third_party目录复制下来就可以了。
此时我们的目录如下:

➜  kratos-http git:(master) tree
.
├── api
│   └── user.proto
├── go.mod
└── third_party
    └── google
        ├── api
        │   ├── annotations.proto
        │   ├── client.proto
        │   ├── field_behavior.proto
        │   ├── http.proto
        │   └── httpbody.proto
        └── protobuf
            ├── any.proto
            ├── api.proto
            ├── compiler
            │   └── plugin.proto
            ├── descriptor.proto
            ├── duration.proto
            ......
6 directories, 19 files
2.3.2 配置goland,protobuf的第三方import地址

我们打开 goland的 “语言和框架”->"Protocol Buffers"
然后把我们自己的项目的 third_party目录加一下。
《go微服务框架Kratos 》连载五:使用protbuf创建http服务器
此时我们的proto文件显示正常了。

三、使用protoc生成pb对应的.go文件

我们把protoc命令放到Makefile里。
在kratos-http目录我们新建一个 Makefile文件

touch Makefile

对应的脚本为

.PHONY: api
# 由 proto 生成接口层代码
api:
    protoc --proto_path=./api \
           --proto_path=./third_party \
            --go_out=paths=source_relative:./api \
            --go-http_out=paths=source_relative:./api \
          user.proto

此时我们执行make命令make api

➜  kratos-http git:(master) ✗ make api

此时在api目录生成了user.pb.go以及user_http.pb.go文件

➜  api git:(master) ✗ tree
.
├── user.pb.go
├── user.proto
└── user_http.pb.go

0 directories, 3 files
➜  api git:(master) ✗ 

然后我再执行一下go mod tidy给新生成的go文件加载依赖

kratos-http git:(master) ✗  go mod tidy

四、实现服务接口

我们打开user_http.pb.go,发现有一个 UserHTTPServer 接口,我们需要实现。
在根目录,建立service文件夹,并且在service文件夹下建一个user.go

mkdir service && cd service && touch user.go

我们打开user.go 写入以下代码:

package service

import (
    "context"
    "github.com/hisheng/kratos-http/api"
)

type UserService struct {
}

func (svc UserService) ListUser(context.Context, *api.ListUserRequest) (*api.ListUserReply, error) {
    return &api.ListUserReply{Id: 100}, nil
}

func (svc UserService) CreateUser(context.Context, *api.CreateUserRequest) (*api.CreateUserReply, error) {
    return nil, nil
}

在这里我们定义了一个UserService,来实现user_http.pb.go里的UserHTTPServer接口。

五、创建http服务器,并注册路由。

我们在根目录,新建一个 server目录,并在server目录下新建一个main.go

mkdir server && cd server && touch main.go

我们打开main.go代码如下:

package main

import (
    "context"
    "github.com/go-kratos/kratos/v2/transport/http"
    "github.com/hisheng/kratos-http/api"
    "github.com/hisheng/kratos-http/service"
    "log"
    "net"
)

func main() {
    ln, err := net.Listen("tcp", ":8080")
    if err != nil {
        log.Fatal(err)
    }
    server := http.NewServer(http.Listener(ln))
    userService := service.UserService{}
    api.RegisterUserHTTPServer(server, userService)

    _ = server.Start(context.Background())
    // _ = server.Serve(ln) 这个也行,不过感觉上面的start更好,
                            // start会调用server.Serve
}

在这里,我们使用了kratos/v2/transport/http的NewServer()来创建服务器。
因为这个方法,兼容了protobuf,注册路由。

点赞
收藏
评论区
推荐文章
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Easter79 Easter79
4年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Easter79 Easter79
4年前
TurnipBit开发板DIY呼吸的吃豆人教程实例
  转载请以链接形式注明文章来源(MicroPythonQQ技术交流群:157816561,公众号:MicroPython玩家汇)  0x00前言  吃豆人是耳熟能详的可爱形象,如今我们的TurnipBit也集成了这可爱的图形,我们这就让他来呼吸了~。  0x01效果展示  先一起看下最终的成品演示视频:  http:/
Wesley13 Wesley13
4年前
0、Spring 注解驱动开发
0、Spring注解驱动开发0.1简介《Spring注解驱动开发》是一套帮助我们深入了解Spring原理机制的教程;现今SpringBoot、SpringCloud技术非常火热,作为Spring之上的框架,他们大量使用到了Spring的一些底层注解、原理,比如@Conditional、@Import、@
Stella981 Stella981
4年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Wesley13 Wesley13
4年前
Java反射例子汇总 Class Constructor Method Filed
一、反射概述  在平常的开发中Java的反射技术很少被用到,一般我们都是使用公司封装或者开源框架。而反射技术已经被包含到底层框架了,因此我们很少接触到。但是有些框架的原理或者源码如果想读懂就必须要理解并会使用反射技术。例如:EventBus、BufferKnife、android的插件化等等都会用到。理解了反射技术能够帮助我们更快的理解相关框架,也可以增
Wesley13 Wesley13
4年前
Java集群优化——dubbo+zookeeper构建高可用分布式集群
不久前,我们讨论过Nginxtomcat组成的集群,这已经是非常灵活的集群技术,但是当我们的系统遇到更大的瓶颈,全部应用的单点服务器已经不能满足我们的需求,这时,我们要考虑另外一种,我们熟悉的内容,就是分布式,而当下流行的Dubbo框架,不容我们忽视,这里,咱们一起来探讨一下这个框架的使用。一,背景  以前我们需要远程调用他人的接口,我们是这么