一、介绍
前几张我们已经学了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目录加一下。
此时我们的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,注册路由。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。