🌐

GolangでCookie付きのWebsocket通信を行う

2021/12/08に公開

意外と情報が無くて苦しんだのでメモ
websocketのライブラリはgorrila/websocketを利用した。
簡単なテストを目的にしたツールのため、実用には耐えないコードであることに注意。

Code

package main

import (
	"net/http/cookiejar"
	"net/url"

	"github.com/gorilla/websocket"
	"github.com/pkg/errors"
)

var (
	host = "nowhere:4649"
	path = "super/websocket/form"
)

func main() {
	u := &url.URL{Scheme: "http", Host: host, Path: path}
	
	jar, err := cookiejar.New(nil)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	cookies := []*http.Cookie{}
	cookie := &http.Cookie{
		Name:   "TASTE_OF_COOKIE",
		Value:  "VERY_DELICIOUS",
		Path:   "/",
		Domain: "localhost",
	}
	cookies = append(cookies, cookie)
	jar.SetCookies(u, cookies)

	dialer := websocket.Dialer{}
	dialer.Jar = jar

	con := url.URL{Scheme: "ws", Host: host, Path: path}
	c, _, err := dialer.Dial(con.String(), nil)
	return c, nil
	
	# websocket send
	err := c.WriteMessage(websocket.TextMessage, []byte("Hello world"))
	if err != nil {
		log.Println("write:", err)
		return
	}
	
	# websocket receive
	_, message, err := c.ReadMessage()
	if err != nil {
		log.Println("read:", err)
		return
	}
	log.Printf("received: %s", message)
}

解説

Cookieの作成とセット

gorilla/websocketでは、dialer.Dial()を呼び出すことでwebsocket通信を確立させることができるが、この時dialer.JarにCookieを持たせることで、通信開始時にCookieを送信することができる。

GoDocより

type Dialer struct {
	// 上略

	// Jar specifies the cookie jar.
	// If Jar is nil, cookies are not sent in requests and ignored
	// in responses.
	Jar http.CookieJar
}

http.CookieJarはただのinterfaceなので、その実装であるnet/http/cookiejarを利用した。

cookiejar.Jarでは、SetCookies()することでCookieをJarにセットすることができる。
この時、第一引数に指定する*url.URLschemehttp,https以外の場合、サイレントにCookieが捨てられることに注意。

GoDocより

SetCookies implements the SetCookies method of the http.CookieJar interface.

It does nothing if the URL's scheme is not HTTP or HTTPS.

Websocket通信

後はいつも通りWriteMessage()ReadMessage()して通信を行うことができる。

感想

Cookieのことをよく分かってないマンだったので、解決の糸口をどこから探るべきなのか苦労した...
GoDocをよく読んだりライブラリのコードを眺めることで解決できたので、そういう地道な作業が大事だと思いました(KONAMI)

Discussion