在Go中提供WebSocket服务

huangapple go评论73阅读模式
英文:

Serving a websocket in Go

问题

我开始尝试使用Go语言和Websockets进行开发,但我觉得我对Go中的Websockets有一些基本的误解。

我想简单地监听一个Websocket连接并进行相应的处理。然而,我在Go中看到的所有示例都是先提供一个网页,然后再连接到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

英文:

I'm starting to play around with websockets + go and well I think I'm misunderstanding something quite basic with websockets in Go.

I'd like to simply listen for a websocket connection and process accordingly. However all examples I see in Go using websocket is serving the web page that then connects to the websocket, is this a requirement?

The following is a basic echo server I have setup:

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())
  }
}

This is the javascript used to connect:

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

However this results in:
WebSocket connection to 'ws://localhost:8080/echo' failed: Unexpected response code: 403

答案1

得分: 16

在使用JavaScript处理Websockets时,你很少需要直接读取帧。说实话,我甚至不确定如何做到这一点。

幸运的是,websocket包已经有一个名为Codec的类型,可以为你完成这个任务。我的建议是使用预定义的websocket.Message编解码器来发送和接收消息。

>Message是一个在WebSocket连接上发送/接收文本/二进制数据的编解码器。要发送/接收文本帧,请使用string类型。要发送/接收二进制帧,请使用[]byte类型。

使用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包无关。

英文:

When working with websockets from Javascript, you will seldom have to read the frames directly. To be honest, I am not even sure how to do that.

Fortunately, the websocket package already has a type, Codec that does this for you. My suggestion is to use the predefined websocket.Message codec to Recieve and Send messages instead.

>Message is a codec to send/receive text/binary data in a frame on WebSocket connection. To send/receive text frame, use string type. To send/receive binary frame, use []byte type.

Using websocket.Message, your webHandler would look something like this:

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)    	
}

And, no, it is not a requirement that Go serves the webpage. The 403 error you received does not have to do with Go or the websocket package.

答案2

得分: 15

我遇到了类似的问题,403错误问题与Go如何处理http Origin header有关:

> Handler是一个简单的接口,用于WebSocket浏览器客户端。默认情况下,它会检查Origin头是否是有效的URL。你可能想在func中验证websocket.Conn.Config().Origin。如果你使用Server而不是Handler,你可以调用websocket.Origin并在你的Handshake func中检查origin。所以,如果你想接受非浏览器客户端,它不发送Origin头,你可以使用Server。它在其Handshake中不检查origin。

为了禁用Origin检查,你必须使用类似以下的代码:

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

至少对我来说(服务器到服务器的WebSocket通信),这解决了问题,我认为如果origin头不匹配,它也可以解决问题。

英文:

I had a similar issue and the 403 error problem is related to how Go treats the http Origin header:

> Handler is a simple interface to a WebSocket browser client. It checks if Origin header is valid URL by default. You might want to verify websocket.Conn.Config().Origin in the func. If you use Server instead of Handler, you could call websocket.Origin and check the origin in your Handshake func. So, if you want to accept non-browser client, which doesn't send Origin header, you could use Server . that doesn't check origin in its Handshake.

In order to disable the Origin check, you must use something like:

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

At least that solved the issue for me (server to server WebSocket communication) and I think it could solve the problem as well if the origin header does not match.

huangapple
  • 本文由 发表于 2013年10月31日 21:49:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/19708330.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定