Go & Socket.io HTTP + WSS on one port with CORS?

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

Go & Socket.io HTTP + WSS on one port with CORS?

问题

全新接触Go语言..显然还在学习语法和基础知识..但我有一个具体的目标..

我想在端口8080上建立一个简单的服务器,可以同时响应HTTP和socket.io(通过/socket.io/ URL),特别是要支持CORS。

我的代码:

package main

import (
    "log"
    "net/http"
    "github.com/rs/cors"
    "github.com/googollee/go-socket.io"
)

func SayHelloWorld(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello, World!"))
}

func main() {

    c := cors.New(cors.Options{
        AllowedOrigins: []string{"*"},
        AllowCredentials: true,
    })

    server, err := socketio.NewServer(nil)
    if err != nil {
        log.Fatal(err)
    }

    server.On("connection", func(so socketio.Socket) {
        log.Println("on connection")
        so.Join("chat")
        so.On("chat message", func(msg string) {
            log.Println("emit:", so.Emit("chat message", msg))
            so.BroadcastTo("chat", "chat message", msg)
        })
        so.On("disconnection", func() {
            log.Println("on disconnect")
        })
    })

    server.On("error", func(so socketio.Socket, err error) {
        log.Println("error:", err)
    })

    http.Handle("/socket.io/", c.Handler(server))
    http.HandleFunc("/", SayHelloWorld)
    log.Println("Serving at localhost:8080...")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

在客户端上,我仍然看到以下错误:
>WebSocket connection to 'wss://api.domain.com/socket.io/?EIO=3&transport=websocket&sid=xNWd9aZvwDnZOrXkOBaC' failed: WebSocket is closed before the connection is established.
>
>(index):1 XMLHttpRequest cannot load https://api.domain.com/socket.io/?EIO=3&transport=polling&t=1420662449235-3932&sid=xNWd9aZvwDnZOrXkOBaC. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://fiddle.jshell.net' is therefore not allowed access.

编辑 #1:

我一直在努力弄清楚为什么无法连接..发现了更令人困惑的一部分?

https://gist.github.com/acoyfellow/167b055da85248c94fc4

上面的代码片段是我的golang服务器代码+用于连接的浏览器代码..这段代码每秒会向后端发送30个HTTP GET请求,而不连接、升级或提供任何错误(客户端或服务器端)..它实际上在攻击自己的后端?

请有人告诉我我是在做一些愚蠢的事情..这真是个难题 Go & Socket.io HTTP + WSS on one port with CORS?

编辑 #2:

我可以通过调整Go中socket.io端点URL的末尾的/来停止这个“DDOS”攻击..所以:mux.Handle("/socket.io", server)改为mux.Handle("/socket.io/", server),现在会产生错误消息和连接尝试,错误响应如下:
>WebSocket connection to 'wss://api.domain.com/socket.io/?EIO=3&transport=websocket&sid=0TzmTM_QtF1TaS4exiwF' failed: Error during WebSocket handshake: Unexpected response code: 400 socket.io-1.2.1.js:2

>GET https://api.domain.com/socket.io/?EIO=3&transport=polling&t=1420743204485-62&sid=0TzmTM_QtF1TaS4exiwF 400 (Bad Request)

英文:

Brand new to Go.. Still obviously learning the syntax and the basics.. But I do have a specific goal in mind..

I'm trying to just get a simple server up on :8080 that can respond to both HTTP and socket.io (via /socket.io/ url), specificaly with CORS.

My code:

package main

import (
     "log"         
     "net/http"
     "github.com/rs/cors"
     "github.com/googollee/go-socket.io"
 )

 func SayHelloWorld(w http.ResponseWriter, r *http.Request) {
     w.Write([]byte("Hello, World!"))
 }

 func main() {

   c := cors.New(cors.Options{
         AllowedOrigins: []string{"*"},
         AllowCredentials: true,
   })

   server, err := socketio.NewServer(nil)
     if err != nil {
         log.Fatal(err)
     }


   server.On("connection", func(so socketio.Socket) {
      log.Println("on connection")
      so.Join("chat")
      so.On("chat message", func(msg string) {
          log.Println("emit:", so.Emit("chat message", msg))
          so.BroadcastTo("chat", "chat message", msg)
      })
      so.On("disconnection", func() {
          log.Println("on disconnect")
      })
   })

   server.On("error", func(so socketio.Socket, err error) {
      log.Println("error:", err)
   })    


   http.Handle("/socket.io/", c.Handler(server))
   http.HandleFunc("/", SayHelloWorld)
   log.Println("Serving at localhost:8080...")
   log.Fatal(http.ListenAndServe(":8080", nil))
}

On the client side I'm still seeing:
>WebSocket connection to 'wss://api.domain.com/socket.io/?EIO=3&transport=websocket&sid=xNWd9aZvwDnZOrXkOBaC' failed: WebSocket is closed before the connection is established.
>
>(index):1 XMLHttpRequest cannot load https://api.domain.com/socket.io/?EIO=3&transport=polling&t=1420662449235-3932&sid=xNWd9aZvwDnZOrXkOBaC. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://fiddle.jshell.net' is therefore not allowed access.

EDIT #1:

So I've been banging my head away trying to understand why I can't connect.. Came across an even more confusing piece of the puzzle?

https://gist.github.com/acoyfellow/167b055da85248c94fc4

The above gist is the code of my golang server + the browser code used to connect.. This code will send 30 HTTP GET requests per second to the backend, without connecting, upgrading, or giving any errors (client or server side).. it essentially DDOS's my own backend?

Someone, please someone tell me I'm doing something stupid.. This is quite the pickle Go & Socket.io HTTP + WSS on one port with CORS?

EDIT #2:

I can stop the "DDOS" by simply adjusting the trailing / on the URL of the socket.io endpoint in Go.. So: mux.Handle("/socket.io", server) to mux.Handle("/socket.io/", server) will now produce error messages and connection attempts with error responses of:
>WebSocket connection to 'wss://api.domain.com/socket.io/?EIO=3&transport=websocket&sid=0TzmTM_QtF1TaS4exiwF' failed: Error during WebSocket handshake: Unexpected response code: 400 socket.io-1.2.1.js:2

>GET https://api.domain.com/socket.io/?EIO=3&transport=polling&t=1420743204485-62&sid=0TzmTM_QtF1TaS4exiwF 400 (Bad Request)

答案1

得分: 13

所以我放弃了使用googoolee的Socket.io实现,转而使用了gorilla的。

我查看了他们的示例:https://github.com/gorilla/websocket/tree/master/examples/chat

查看了他们的文档:http://www.gorillatoolkit.org/pkg/websocket
-- 在"Origin Considerations"下面我找到了:

>通过指定一个始终返回true的函数,应用程序可以允许来自任何来源的连接:
>
>var upgrader = websocket.Upgrader{
> CheckOrigin: func(r *http.Request) bool { return true },
> }

我将这个CheckOrigin函数添加到了他们示例中的conn.go文件中,成功地让一个支持CORS的Socket服务器与浏览器通信。

作为对Golang的初次尝试,这既令人沮丧又有趣.. 给其他学习者加一分。

英文:

So I gave up using googoolee's Socket.io implementation and went with gorilla's.

I checked out their examples: https://github.com/gorilla/websocket/tree/master/examples/chat

Checked out their docs: http://www.gorillatoolkit.org/pkg/websocket
-- Under Origin Considerations I found:

>An application can allow connections from any origin by specifying a function that always returns true:
>
>var upgrader = websocket.Upgrader{
> CheckOrigin: func(r *http.Request) bool { return true },
> }

I added this CheckOrigin function to the conn.go file in their example, and was able to get a CORS socket server talking to a browser.

As a first adventure into Golang, this was frustrating and fun.. +1 to anyone else learning

答案2

得分: 3

你是不是指的是http + ws或https + wss?如果你从wss中去掉一个s,你应该能够连接。

如果你想要为Web Socket(wss)使用TLS,那么你需要使用http.ListenAndServeTLS。

英文:

Don't you mean http + ws or https + wss. If you remove a s from wss, you should be able to connect.

If you want tls for web socket (wss), then you need to http.ListenAndServeTLS.

答案3

得分: 1

似乎CORS不适用于WebSockets。根据相关问题的回答:“使用WebSocket时,有一个'origin'头,浏览器必须使用包含打开WS连接的JS的HTML的来源来填充它。”

如此所述:
https://stackoverflow.com/questions/11076658/cross-origin-websockets-with-golang

英文:

It appears that CORS does not apply to WebSockets. Per this related question "With WebSocket, there is an "origin" header, which browser MUST fill with the origin of the HTML containing the JS that opens the WS connection."

As stated here:
https://stackoverflow.com/questions/11076658/cross-origin-websockets-with-golang

答案4

得分: 0

在你的SayHelloWorld函数中,可以添加以下内容:

w.Header().Set("Access-Control-Allow-Origin", "*")

或者,可能更好的方式是:

if origin := r.Header.Get("Origin"); origin != "" {
  w.Header().Set("Access-Control-Allow-Origin", origin)
}

请注意,这些代码片段是用Go语言编写的,用于设置HTTP响应头中的"Access-Control-Allow-Origin"字段,以实现跨域资源共享(CORS)。第一个代码片段将允许来自任何来源的请求访问资源,而第二个代码片段将根据请求头中的"Origin"字段来设置"Access-Control-Allow-Origin"字段,从而允许特定来源的请求访问资源。

英文:

How about in your SayHelloWorld func, adding something like:

w.Header().Set("Access-Control-Allow-Origin", "*")

Or, possibly better:

if origin := r.Header.Get("Origin"); origin != "" {
  w.Header().Set("Access-Control-Allow-Origin", origin)
}

答案5

得分: 0

我遇到了与普通的ajax调用类似的问题。这需要在前端和后端都进行更多的工作。我相信像jQuery或AngularJS这样的流行前端库可以很好地处理这些问题。

我看到你正在使用https://github.com/rs/cors包,但你没有包含该包的使用方法。下面是只使用Go标准包实现的代码:

type CrossOriginServer struct {}

func (s *CrossOriginServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
    // 你可能需要在这里添加一些其他的头部信息
    allowHeaders := "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization"
    if origin := req.Header.Get("Origin"); validOrigin(origin) {
        rw.Header().Set("Access-Control-Allow-Origin", origin)
        rw.Header().Set("Access-Control-Allow-Methods", "POST, PUT, PATCH, GET, DELETE")
        rw.Header().Set("Access-Control-Allow-Headers", allowHeaders)
    }
    if req.Method == "OPTIONS" {
        return
    }

    // 如果你想的话,你可以在这里使用gorilla/mux或任何其他路由包
    mux := http.NewServeMux()
    mux.Handle("/socket.io/", c.Handler(server))
    mux.HandleFunc("/", SayHelloWorld)

    mux.ServeHTTP(rw, req)
}

func validOrigin(origin string) bool {
    allowOrigin := []string{
        "http://localhost:8081",
        "http://example.com",
    }

    for _, v := range allowOrigin {
        if origin == v {
            return true
        }
    }

    return false
}

func main() {
    // 做你的事情
    // ...
    // ...

    http.ListenAndServe(":8080", &CrossOriginServer{})
}

希望对你有帮助!

英文:

I get the similar problerm with normal ajax call. It require more work in both front-end and backend. I belive most popular front-end libs liek JQuery or AngularJS handle these very well.
I see you're using the https://github.com/rs/cors package but you don't include the usage of that package, here is the implement with only Go std package:

type CrossOriginServer struct {}

func (s *CrossOriginServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	// you may need to add some more headers here
	allowHeaders := "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization"
	if origin := req.Header.Get("Origin"); validOrigin(origin) {
		rw.Header().Set("Access-Control-Allow-Origin", origin)
		rw.Header().Set("Access-Control-Allow-Methods", "POST, PUT, PATCH, GET, DELETE")
		rw.Header().Set("Access-Control-Allow-Headers", allowHeaders)
	}
	if req.Method == "OPTIONS" {
		return
	}

	// if you want, you can use gorilla/mux or any routing package here
	mux := http.NewServeMux()
	mux.Handle("/socket.io/", c.Handler(server))
	mux.HandleFunc("/", SayHelloWorld)

	mux.ServeHTTP(rw, req)
}

func validOrigin(origin string) bool {
	allowOrigin := []string{
		"http://localhost:8081",
		"http://example.com"
	}

	for _, v := range allowOrigin {
		if origin == v {
			return true
		}
	}

	return false
}

func main() {
	// do you stuff
	// ...
	// ...

	http.ListenAndServe(":8080", &CrossOriginServer{})
}

huangapple
  • 本文由 发表于 2015年1月8日 04:26:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/27828052.html
匿名

发表评论

匿名网友

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

确定