2022年8月20日 星期六

Go 開發筆記 - 簡易 WebSocket Client 練習,WSS 與 Skip SSL Check

公司的 WebSocket Server 使用 node.js Primus 建構服務,最近正在調整架構,弄隻 WebSocket Client 交叉比對,這時就想到 Golang 可以練一下 XD 預設先以 PTT 的 WebSocket 為例 wss://ws.ptt.cc/bbs 練習,而 PTT WebSocket 連線時,有檢查 Request Header 的 Origin 欄位的,完整的用法請直接使用 https://term.ptt.cc 。

實作上,直接用 Gorilla WebSocket 即可,用他建制 WebSocket server 跟 client。

此外,對於 WebSocket over SSL (wss) 連線瑣事上,若要處理 SKIP SSL Check 這件事,可以這樣處理:

// https://pkg.go.dev/crypto/tls
type zeroSource struct{}
func (zeroSource) Read(b []byte) (n int, err error) {
    for i := range b { 
        b[i] = 0 
    }   
    return len(b), nil 
}

func main() {

// ...

    var dialer ws.Dialer
    if *skipSSLCheck {
        fmt.Println("[IFNO] Skip SSL check")
        // https://github.com/gorilla/websocket/blob/master/client.go
        // https://github.com/gorilla/websocket/blob/master/tls_handshake.go
        dialer = ws.Dialer{
            Subprotocols: []string{},
            ReadBufferSize: 2048,
            WriteBufferSize: 2048,
            TLSClientConfig: &tls.Config{
                Rand: zeroSource{},
                InsecureSkipVerify: true,
            },
        }
    } else {
        dialer = ws.Dialer{
            Subprotocols: []string{},
            ReadBufferSize: 2048,
            WriteBufferSize: 2048,
        }
    }
    fmt.Println("[IFNO] try to connect to: ", connectToURL)

// ...

}

至於跟 node.js Primus WebSocket server 溝通時,會有 PING/PONG 的 heartbeat 檢驗,目前偷懶等收到 server 詢問時才回,此外,實際上可以靠 messageType (Control Messages) 來判斷:

    go func() {
        defer func() {
            wg.Done()
        }()
        for {
            _, p, err := conn.ReadMessage()
            if err == nil {
                cmd := string(p)
                fmt.Println("SERVER> ", cmd)

                    if strings.Index(cmd, "\"primus::ping::") >= 0 {
                        text := fmt.Sprintf("\"primus::ping::%d\"", time.Now().UnixMilli())
                        fmt.Println("CLIENT:AUTO> [",text,"]")
                        conn.WriteMessage(ws.TextMessage, []byte(text))
                    }

            } else {
                fmt.Println("SERVER:ERROR> ", err)
                break
            }
        }
        fmt.Println("[IFNO] server error")
    }()

更多完整的資訊,就直接參考 github.com/changyy/go-ws-client

沒有留言:

張貼留言