本節完整程式碼:GitHub
本文是使用 ReactJS 和 Go 來構建聊天應用程式的系列文章的第 2 部分。你可以在這裡找到第 1 部分 - 初始化設定
現在我們已經建立好了基本的前端和後端,現在需要來完善一些功能了。
在本節中,我們將實現一個基於 WebSocket 的伺服器。
在該系列教程結束時,我們將有一個可以與後端雙向通訊的前端應用程式。
服務
我們可以使用 github.com/gorilla/websocket
包來設定 WebSocket 服務以及處理 WebSocket 連線的讀寫操作。
這需要在我們的 backend/
目錄中執行此命令來安裝它:
$ go get github.com/gorilla/websocket
複製程式碼
一旦我們成功安裝了這個包,我們就可以開始構建我們的 Web 服務了。我們首先建立一個非常簡單的 net/http
服務:
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
。
WebSocket 協議
在開始寫程式碼之前,我們需要了解一下理論。
WebSockets 可以通過 TCP 連線進行雙工通訊。這讓我們可以通過單個 TCP 套接字來傳送和監聽訊息,從而避免通過輪詢 Web 伺服器去通訊,每次輪詢操作都會執行 TCP 握手過程。
WebSockets 大大減少了應用程式所需的網路頻寬,並且使得我們在單個伺服器例項上維護大量客戶端。
連線
WebSockets 肯定有一些值得考慮的缺點。比如一旦引入狀態,在跨多個例項擴充套件應用程式的時候就變得更加複雜。
在這種場景下需要考慮更多的情況,例如將狀態儲存在訊息代理中,或者儲存在資料庫/記憶體快取中。
實現
在實現 WebSocket 服務時,我們需要建立一個端點,然後將該端點的連線從標準的 HTTP 升級到 WebSocket。
值得慶幸的是,gorilla/websocket
包提供了我們所需的功能,可以輕鬆地將 HTTP 連線升級到 WebSocket 連線。
注意 - 你可以檢視官方 WebSocket 協議的更多資訊:RFC-6455
建立 WebSocket 服務端
現在已經瞭解了理論,來看看如何去實踐。我們建立一個新的端點 /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