Обслуживание веб-узла в Go

Я начинаю поиграть с websockets + пойти и хорошо. Думаю, я неправильно понимаю что-то общее с websockets в Go.

Я бы хотел просто прослушать подключение к веб-сокету и обработать его соответствующим образом. Однако все примеры, которые я вижу в Go, используя websocket, служат веб-странице, которая затем подключается к websocket, это требование?

Ниже приведен базовый эхо-сервер, который у меня установлен:

package main

import (
  "fmt"
  "code.google.com/p/go.net/websocket"
  "net/http"
)

func webHandler(ws *websocket.Conn) {
  var s string
  fmt.Fscan(ws, &s)
  fmt.Println("Received: ", s)
}

func main() {
  fmt.Println("Starting websock server: ")
  http.Handle("/echo", websocket.Handler(webHandler))
  err := http.ListenAndServe(":8080", nil)
  if err != nil {
    panic("ListenAndServe: " + err.Error())
  }
}

Это javascript, используемый для подключения:

ws = new WebSocket("ws://localhost:8080/echo");
ws.onmessage = function(e) {
    console.log("websock: " + e.data);
};

Однако это приводит к:  Соединение WebSocket с 'ws://localhost: 8080/echo' не выполнено: Неожиданный код ответа: 403

Ответ 1

При работе с веб-сайтами из Javascript вам редко приходится читать фреймы напрямую. Честно говоря, я даже не знаю, как это сделать.

К счастью, пакет websocket уже имеет тип Codec, который делает это для вас. Мое предложение состоит в том, чтобы использовать предопределенный код websocket.Message вместо Recieve и Send.

Сообщение представляет собой кодек для отправки/получения текстовых/двоичных данных в фрейме в соединении с WebSocket. Для отправки/получения текстового фрейма используйте тип строки. Чтобы отправить/получить двоичный фрейм, используйте [] тип байта.

Используя websocket.Message, ваш webHandler будет выглядеть примерно так:

func webHandler(ws *websocket.Conn) {
    var in []byte
    if err := websocket.Message.Receive(ws, &in); err != nil {
        return
    }
    fmt.Printf("Received: %s\n", string(in))
    websocket.Message.Send(ws, in)      
}

И нет, это не требование, чтобы Go обслуживал веб-страницу. Полученная ошибка 403 не связана с Go или пакетом websocket.

Ответ 2

У меня была аналогичная проблема, и проблема с ошибкой 403 связана с тем, как Go рассматривает заголовок http Origin:

Обработчик - это простой интерфейс для клиента браузера WebSocket. Он проверяет, является ли заголовок Origin действительным URL по умолчанию. Возможно, вы захотите проверить websocket.Conn.Config(). Начало в func. Если вы используете сервер вместо обработчика, вы можете вызвать websocket.Origin и проверить происхождение в вашей функции Handshake. Итак, если вы хотите принять не-браузерный клиент, который не отправляет заголовок Origin, вы можете использовать Server. который не проверяет происхождение в своем рукопожатии.

Чтобы отключить проверку Origin, вы должны использовать что-то вроде:

http.HandleFunc("/echo",
    func (w http.ResponseWriter, req *http.Request) {
        s := websocket.Server{Handler: websocket.Handler(webHandler)}
        s.ServeHTTP(w, req)
    });

По крайней мере, это решило проблему для меня (связь между сервером и сервером WebSocket), и я думаю, что она также может решить проблему, если заголовок источника не совпадает.