使用 CORS 在一个端口上运行 & Socket.io HTTP + WSS?
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请求到后端,没有连接、升级或出现任何错误(客户端或服务器端).. 它本质上是我自己的后端的 DDOS?
有人,请有人告诉我我在做一些愚蠢的事情..这真是泡菜:P
编辑#2:
我可以通过简单地调整 Go 中 socket.io 端点的 URL 上的尾随 /
来停止 "DDOS"。所以:mux.Handle("/socket.io", server)
to 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)
如何在您的 SayHelloWorld
函数中添加如下内容:
w.Header().Set("Access-Control-Allow-Origin", "*")
或者,可能更好:
if origin := r.Header.Get("Origin"); origin != "" {
w.Header().Set("Access-Control-Allow-Origin", origin)
}
我在正常的 ajax 调用中遇到了类似的问题。它需要在前端和后端做更多的工作。我相信最流行的前端库 liek JQuery 或 AngularJS 处理得很好。
我看到你正在使用 https://github.com/rs/cors 包,但你没有包括该包的用法,这里是只有 Go std 包的实现:
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{})
}
CORS 似乎不适用于 WebSockets。根据这个相关问题 "With WebSocket, there is an "origin" header,哪个浏览器必须填写包含打开 WS 连接的 JS 的 HTML 的来源。"
所以我放弃了使用 googoolee 的 Socket.io 实现并选择了大猩猩的实现。
我查看了他们的示例:https://github.com/gorilla/websocket/tree/master/examples/chat
查看了他们的文档:http://www.gorillatoolkit.org/pkg/websocket
-- 在 Origin Considerations 我发现:
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 },
}
我在他们的示例中将此 CheckOrigin
函数添加到 conn.go
文件,并且能够获得与浏览器通信的 CORS 套接字服务器。
作为 Golang 的第一次冒险,这既令人沮丧又有趣.. +1 给其他学习者
你不是说 http + ws 或 https + wss 吗?如果你把wss中的一个s去掉,应该可以连接。
如果你想要 web 套接字 (wss) 的 tls,那么你需要 http.ListenAndServeTLS。
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请求到后端,没有连接、升级或出现任何错误(客户端或服务器端).. 它本质上是我自己的后端的 DDOS?
有人,请有人告诉我我在做一些愚蠢的事情..这真是泡菜:P
编辑#2:
我可以通过简单地调整 Go 中 socket.io 端点的 URL 上的尾随 /
来停止 "DDOS"。所以:mux.Handle("/socket.io", server)
to 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)
如何在您的 SayHelloWorld
函数中添加如下内容:
w.Header().Set("Access-Control-Allow-Origin", "*")
或者,可能更好:
if origin := r.Header.Get("Origin"); origin != "" {
w.Header().Set("Access-Control-Allow-Origin", origin)
}
我在正常的 ajax 调用中遇到了类似的问题。它需要在前端和后端做更多的工作。我相信最流行的前端库 liek JQuery 或 AngularJS 处理得很好。
我看到你正在使用 https://github.com/rs/cors 包,但你没有包括该包的用法,这里是只有 Go std 包的实现:
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{})
}
CORS 似乎不适用于 WebSockets。根据这个相关问题 "With WebSocket, there is an "origin" header,哪个浏览器必须填写包含打开 WS 连接的 JS 的 HTML 的来源。"
所以我放弃了使用 googoolee 的 Socket.io 实现并选择了大猩猩的实现。
我查看了他们的示例:https://github.com/gorilla/websocket/tree/master/examples/chat
查看了他们的文档:http://www.gorillatoolkit.org/pkg/websocket -- 在 Origin Considerations 我发现:
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 }, }
我在他们的示例中将此 CheckOrigin
函数添加到 conn.go
文件,并且能够获得与浏览器通信的 CORS 套接字服务器。
作为 Golang 的第一次冒险,这既令人沮丧又有趣.. +1 给其他学习者
你不是说 http + ws 或 https + wss 吗?如果你把wss中的一个s去掉,应该可以连接。
如果你想要 web 套接字 (wss) 的 tls,那么你需要 http.ListenAndServeTLS。