导语
这一篇文章会陆续介绍Micro API中的rpc模式和websocket模式,废话不多说,阅读前要保持头脑清晰就可以了。
RPC模式
首先同样定义我们的api.proto和之前的代码一样
syntax = "proto3";
service Example {
rpc Call(CallRequest) returns(CallResponse) {};
}
service Foo {
rpc Bar(EmptyRequest) returns(EmptyResponse) {};
}
message CallRequest {
string name = 1;
}
message CallResponse {
string message = 2;
}
message EmptyRequest {
}
message EmptyResponse {
}
执行protoc命令,生成我们的代码
protoc --go_out=. --micro_out=. proto/api.proto
来看我们的服务端代码,实现我们的服务方法
type Example struct{}
type Foo struct{}
// Call 方法会接收由API层转发,路由为/example/call的HTTP请求
func (e *Example) Call(ctx context.Context, req *proto.CallRequest, rsp *proto.CallResponse) error {
log.Print("收到 Example.Call 请求")
if len(req.Name) == 0 {
return errors.BadRequest("go.micro.api.example", "no content")
}
rsp.Message = "RPC Call收到了你的请求 " + req.Name
return nil
}
// Bar 方法会接收由API层转发,路由为/example/foo/bar的HTTP请求
// 该接口我们什么参数也不处理,只打印信息
func (f *Foo) Bar(ctx context.Context, req *proto.EmptyRequest, rsp *proto.EmptyResponse) error {
log.Print("收到 Foo.Bar 请求")
return nil
}
编写我们的主函数
func main() {
service := micro.NewService(
micro.Name("go.micro.api.example"),
)
service.Init()
// 注册 example 接口
proto.RegisterExampleHandler(service.Server(), new(Example))
// 注册 foo 接口
proto.RegisterFooHandler(service.Server(), new(Foo))
if err := service.Run(); err != nil {
log.Fatal(err)
}
}
现在测试我们的代码
以rpc模式运行API
micro api --handler=rpc
运行服务端代码
go run rpc.go
使用postman进行测试
WebSocket模式
Websocket时一种双向通信的套接字,可以主动向服务端发送请求,并完成响应,这里不再进行详细介绍,如果有不懂的欢迎在我的知识星球进行讨论。加入方式如下
首先编写一个客户端的index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Websocket Stream</title>
<script src="./main.js"></script>
<style>
table {
table-layout: fixed;
}
td {
border: 2px solid green;
}
td input {
width: 100%;
box-sizing: border-box;
}
</style>
</head>
<body>
<h2>Websocket Stream</h2>
<table>
<tr>
<td valign="top" width="25%">
<p>
<form>
<p> Name: <br>
<input id="name" name="name" type="text"/>
</p>
<p>
<button type="button" id="send">Send</button>
<button type="button" id="cancel">Cancel</button>
</p>
<p>
<button type="button" id="open">Open Connection</button>
</p>
</form>
</p>
</td>
<td valign="top" width="75%">
<div id="output"/>
</td>
</tr>
</table>
</body>
</html>
以上需要注意的时引用了main.js,在第六行,代码如下,这里需要注意的是,在第2行定义了一个变量,这个变量存储了我们连接socket的地址,然后使用new WebSocket(wsUri)建立了一个websocket对象,这个对象监听了4个事件,分别是
onopen:监听与服务端连接成功执行代码
onclose:监听与服务端断开时执行相应代码
onmessage:监听收到服务端信息时执行代码
onerror:监听与服务端通信期间出现了错误,执行相应代码
window.addEventListener("load", function (evt) {
var wsUri = "ws://localhost:8080/websocket"
var output = document.getElementById("output");
var nameTxt = document.getElementById("name");
var ws;
var print = function (message) {
var d = document.createElement("div");
d.innerHTML = message;
output.appendChild(d);
};
(function () {
ws = new WebSocket(wsUri);
ws.onopen = function (evt) {
print('<span style="color: green;">Connection Open</span>');
}
ws.onclose = function (evt) {
print('<span style="color: red;">Connection Closed</span>');
ws = null;
}
ws.onmessage = function (evt) {
print('<span style="color: blue;">Update: </span>' + evt.data);
}
ws.onerror = function (evt) {
print('<span style="color: red;">Error: </span>' + evt.data);
}
})();
document.getElementById("send").onclick = function (evt) {
if (!ws) {
return false
}
var msg = {hi: nameTxt.value}
req = JSON.stringify(msg)
print('<span style="color: blue;">Sent request: </span>' + req);
ws.send(JSON.stringify(msg));
return false;
};
document.getElementById("cancel").onclick = function (evt) {
if (!ws) {
return false;
}
ws.close();
print('<span style="color: red;">Request Canceled</span>');
return false;
};
document.getElementById("open").onclick = function (evt) {
if (!ws) {
newSocket()
}
return false;
};
})
客户端写好了,我们就可以编写我们的服务端,首先需要导入相应的包
"github.com/gorilla/websocket"
"github.com/micro/go-micro/web"
服务端对socket进行升级时,这里为了方便直接验证通过
var upGrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}
编写一个读取客户端消息的函数,这里需要明白的upGrader.Upgrade(w, r, nil)
是升级HTTP并连接到websocket上获得一个websocket连接。中间使用了一个无限循环进行读取消息和写入消息。
func hi(w http.ResponseWriter, r *http.Request) {
c, err := upGrader.Upgrade(w, r, nil)
if err != nil {
log.Printf("upgrade: %s", err)
return
}
defer c.Close()
for {
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
log.Printf("recv: %s", message)
err = c.WriteMessage(mt, message)
if err != nil {
log.Println("write:", err)
break
}
}
}
在主函数中注册我们的服务
service := web.NewService(
web.Name("go.micro.web.websocket"),
)
if err := service.Init(); err != nil {
log.Fatal("Init", err)
}
// static files
service.Handle("/websocket/", http.StripPrefix("/websocket/", http.FileServer(http.Dir("html"))))
// websocket interface
service.HandleFunc("/websocket", hi)
if err := service.Run(); err != nil {
log.Fatal("Run: ", err)
}
现在我们运行测试一下
micro api --handler=web --namespace=go.micro.web
go run .\web.go
打开浏览器输入
推荐阅读
- 微服务系列笔记之API事件订阅模式和元数据模式
- RabbitMQ系列笔记介绍篇
- Golang中Modle包的使用
- goriila context深入学习笔记
- Go Context深入学习笔记
- 基于Nginx和Consul构建高可用及自动发现的Docker服务架构
- 关于log日志的深入学习笔记
本文欢迎转载,转载请联系作者,谢谢!
- 公众号【常更新】:无崖子天下无敌
- GitHub:https://github.com/yuwe1
- 博客地址【定期更新】:https://mowuya.cn/
有疑问加站长微信联系(非本文作者)