本节完整代码:GitHubcss
本文是使用 ReactJS 和 Go 来构建聊天应用程序的系列文章的第 2 部分。你能够在这里找到第 1 部分 - 初始化设置html
如今咱们已经创建好了基本的前端和后端,如今须要来完善一些功能了。前端
在本节中,咱们将实现一个基于 WebSocket 的服务器。react
在该系列教程结束时,咱们将有一个能够与后端双向通讯的前端应用程序。git
咱们可使用 github.com/gorilla/websocket
包来设置 WebSocket 服务以及处理 WebSocket 链接的读写操做。github
这须要在咱们的 backend/
目录中运行此命令来安装它:golang
$ go get github.com/gorilla/websocket
复制代码
一旦咱们成功安装了这个包,咱们就能够开始构建咱们的 Web 服务了。咱们首先建立一个很是简单的 net/http
服务:web
package main
import (
"fmt"
"net/http"
)
func setupRoutes() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Simple Server")
})
}
func main() {
setupRoutes()
http.ListenAndServe(":8080", nil)
}
复制代码
能够经过调用 go run main.go
来启动服务,该服务将监听 http://localhost:8080 。若是用浏览器打开此链接,能够看到输出 Simple Server
。shell
在开始写代码以前,咱们须要了解一下理论。数据库
WebSockets 能够经过 TCP 链接进行双工通讯。这让咱们能够经过单个 TCP 套接字来发送和监听消息,从而避免经过轮询 Web 服务器去通讯,每次轮询操做都会执行 TCP 握手过程。
WebSockets 大大减小了应用程序所需的网络带宽,而且使得咱们在单个服务器实例上维护大量客户端。
WebSockets 确定有一些值得考虑的缺点。好比一旦引入状态,在跨多个实例扩展应用程序的时候就变得更加复杂。
在这种场景下须要考虑更多的状况,例如将状态存储在消息代理中,或者存储在数据库/内存缓存中。
在实现 WebSocket 服务时,咱们须要建立一个端点,而后将该端点的链接从标准的 HTTP 升级到 WebSocket。
值得庆幸的是,gorilla/websocket
包提供了咱们所需的功能,能够轻松地将 HTTP 链接升级到 WebSocket 链接。
注意 - 你能够查看官方 WebSocket 协议的更多信息:RFC-6455
如今已经了解了理论,来看看如何去实践。咱们建立一个新的端点 /ws
,咱们将从标准的 http
端点转换为 ws
端点。
此端点将执行 3 项操做,它将检查传入的 HTTP 请求,而后返回 true
以打开咱们的端点到客户端。而后,咱们使用定义的 upgrader
升级为 WebSocket 链接。
最后,咱们将开始监听传入的消息,而后将它们打印出来并将它们传回相同的链接。这可让咱们验证前端链接并重新建立的 WebSocket 端点来发送/接收消息:
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/websocket"
)
// 咱们须要定义一个 Upgrader
// 它须要定义 ReadBufferSize 和 WriteBufferSize
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
// 能够用来检查链接的来源
// 这将容许从咱们的 React 服务向这里发出请求。
// 如今,咱们能够不须要检查并运行任何链接
CheckOrigin: func(r *http.Request) bool { return true },
}
// 定义一个 reader 用来监听往 WS 发送的新消息
func reader(conn *websocket.Conn) {
for {
// 读消息
messageType, p, err := conn.ReadMessage()
if err != nil {
log.Println(err)
return
}
// 打印消息
fmt.Println(string(p))
if err := conn.WriteMessage(messageType, p); err != nil {
log.Println(err)
return
}
}
}
// 定义 WebSocket 服务处理函数
func serveWs(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.Host)
// 将链接更新为 WebSocket 链接
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
}
// 一直监听 WebSocket 链接上传来的新消息
reader(ws)
}
func setupRoutes() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Simple Server")
})
// 将 `/ws` 端点交给 `serveWs` 函数处理
http.HandleFunc("/ws", serveWs)
}
func main() {
fmt.Println("Chat App v0.01")
setupRoutes()
http.ListenAndServe(":8080", nil)
}
复制代码
若是没有问题的话,咱们使用 go run main.go
来启动服务。
如今已经设置好了服务,咱们须要一些可以与之交互的东西。这是咱们的 ReactJS 前端发挥做用的地方。
咱们先尽可能让客户端保持简单,并定义一个 api/index.js
文件,它将包含 WebSocket 链接的代码。
// api/index.js
var socket = new WebSocket("ws://localhost:8080/ws");
let connect = () => {
console.log("Attempting Connection...");
socket.onopen = () => {
console.log("Successfully Connected");
};
socket.onmessage = msg => {
console.log(msg);
};
socket.onclose = event => {
console.log("Socket Closed Connection: ", event);
};
socket.onerror = error => {
console.log("Socket Error: ", error);
};
};
let sendMsg = msg => {
console.log("sending msg: ", msg);
socket.send(msg);
};
export { connect, sendMsg };
复制代码
所以,在上面的代码中,咱们定义了咱们随后导出的 2 个函数。分别是 connect()
和 sendMsg(msg)
。
第一个函数,connect()
函数,链接 WebSocket 端点,并监听例如与 onopen
成功链接之类的事件。若是它发现任何问题,例如链接关闭的套接字或错误,它会将这些问题打印到浏览器控制台。
第二个函数,sendMsg(msg)
函数,容许咱们使用 socket.send()
经过 WebSocket 链接从前端发送消息到后端。
如今咱们在 React 项目中更新 App.js
文件,添加对 connect()
的调用并建立一个触发 sendMsg()
函数的 <button />
元素。
// App.js
import React, { Component } from "react";
import "./App.css";
import { connect, sendMsg } from "./api";
class App extends Component {
constructor(props) {
super(props);
connect();
}
send() {
console.log("hello");
sendMsg("hello");
}
render() {
return (
<div className="App"> <button onClick={this.send}>Hit</button> </div>
);
}
}
export default App;
复制代码
使用 npm start
成功编译后,咱们能够在浏览器中看到一个按钮,若是打开浏览器控制台,还能够看到成功链接的 WebSocket 服务运行在 http://localhost:8080。
问题 - 单击此按钮会发生什么?你在浏览器的控制台和后端的控制台中看到了什么输出?
结束了本系列的第 2 部分。咱们已经可以建立一个很是简单的 WebSocket 服务,它能够回显发送给它的任何消息。
这是开发应用程序的关键一步,如今咱们已经启动并运行了基本框架,咱们能够开始考虑实现基本的聊天功能并让这个程序变得更有用!
下一节:Part 3 - 前端实现
原文:tutorialedge.net/projects/ch…
做者:Elliot Forbes 译者:咔叽咔叽 校对:polaris1119