背景知识
API服务
前端发送请求时,需要和后端确定协议、服务器地址、路径、参数、数据类型(json,XML,二进制流)、数据编码、安全性(那里存放token)、错误处理等。
GRPC
- 协议:http2
- http2与 http1 具有相同的方法、header、body。
- http2采用二进制传输数据。
- http2采用流式传输,传统的传输是服务器生成所有的数据之后才传输回来,而流式传输生成多少传输多少。
- http2采用多路复用,而多路复用可以多个请求共用一个连接,而http1也可以共用,但是必须要前一个请求回来再发送下一个。http2不需要。
- 方法:post
- 路径:/service/method
- 参数:body
- 安全行:http2+token放在header里
- 数据:二进制流
- 数据结构:ProtoBuf
优点
高效数据传输,语言无关的领域模型定义。
ProtoBuf
ProtoBuf的使用
创建trip.proto文件
//trip.proto
syntax = "proto3";
package coolcar ;
// 生成的路径 生成的包名
option go_package = "coolcar/proto/gen/go;trippb";
message Trip{
string start = 1;
string end = 2;
int64 duration_sec = 3;
int64 fee_cnet = 4;
}
通过命令
protoc -I=D:\GoCode\coolcar\server\proto --go_out=paths=source_relative:gen/go trip.proto
编译生成trip.pb.go文件(部分代码)
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.31.0
// protoc v3.13.0
// source: trip.proto
package trippb
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Trip struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
//下划线的变量名,编译成驼峰形式
Start string `protobuf:"bytes,1,opt,name=start,proto3" json:"start,omitempty"`
End string `protobuf:"bytes,2,opt,name=end,proto3" json:"end,omitempty"`
DurationSec int64 `protobuf:"varint,3,opt,name=duration_sec,json=durationSec,proto3" json:"duration_sec,omitempty"`
FeeCnet int64 `protobuf:"varint,4,opt,name=fee_cnet,json=feeCnet,proto3" json:"fee_cnet,omitempty"`
}
在main.go中使用trip.pb.go
//main.go
package main
import (
trippb "coolcar/proto/gen/go"
"encoding/json"
"fmt"
"google.golang.org/protobuf/proto"
)
func main() {
trip:=trippb.Trip{
Start: "abc",
End: "def",
DurationSec: 1000,
FeeCnet: 1000,
}
//trip中的锁等值无法复制,所以传入地址值
fmt.Println(&trip)
//编码trip为二进制
b,err:=proto.Marshal(&trip)
if err!=nil{
panic(err)
}
fmt.Printf("%x",b)
//解码二进制到trip
var trip2 trippb.Trip
err=proto.Unmarshal(b,&trip2)
if err != nil {
panic(err)
}
fmt.Println(&trip2)
//trip编码为json
b,err=json.Marshal(&trip2)
if err != nil {
panic(err)
}
fmt.Printf("%s",b)
}
复合类型和枚举类型
message Location {
double latitude = 1;
double longtitue = 2;
}
//枚举类型
enum TripStatus {
TS_NOT_SPECIFIED = 0;
NOT_START = 1;
IN_PROGRESS = 2;
FINISHED = 3;
PAID = 4;
}
message Trip{
string start = 1;
string end = 2;
int64 duration_sec = 3;
int64 fee_cnet = 4;
//复合类型
Location start_pos = 5;
Location end_pos = 6;
//切片类型
repeated Location path_locations = 7;
}
初始化复合类型
trip:=trippb.Trip{
Start: "abc",
End: "def",
DurationSec: 1000,
FeeCnet: 1000,
EndPos: &trippb.Location{
Latitude:100,
Longtitue:100,
},
//使用指针来赋值
StartPos: &trippb.Location{
Latitude:100,
Longtitue:100,
},
PathLocations: []*trippb.Location{
{
Latitude:100,
Longtitue:100,
},
{
Latitude:100,
Longtitue:100,
},
},
//枚举形式的赋值
Status: trippb.TripStatus_FINISHED,
}
protobuf字段的可选性
任何字段都可以不指定,默认为零值。