分享
  1. 首页
  2. 文章

微服务系列笔记之RPC和WebSocket

陌无崖 · · 1497 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

导语

这一篇文章会陆续介绍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进行测试


image

WebSocket模式

Websocket时一种双向通信的套接字,可以主动向服务端发送请求,并完成响应,这里不再进行详细介绍,如果有不懂的欢迎在我的知识星球进行讨论。加入方式如下


image

首先编写一个客户端的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

打开浏览器输入


image

image

推荐阅读


本文欢迎转载,转载请联系作者,谢谢!


打开微信扫一扫,关注微信公众号

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:陌无崖

查看原文:微服务系列笔记之RPC和WebSocket

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1497 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏