go-socket.io
go-socket.io copied to clipboard
solve the problem of CORS and websocket 403
I found some problems,When I used this class library.My web page and socket service are not in the same domain,so it leads to the CORS problem. i try to solve CORS problem,but i cant not find any documentation. then I search in issues and find some useful code.finally solved it. To help more people solve the same problem, I'm going to share my code.
use branch 1.4 and socket-io.js 1.4 main.go
package main
import (
"fmt"
"log"
"net/http"
socketio "github.com/googollee/go-socket.io"
"github.com/rs/cors"
"github.com/googollee/go-engine.io/transport/polling"
"github.com/googollee/go-engine.io/transport/websocket"
"github.com/googollee/go-engine.io"
"github.com/googollee/go-engine.io/transport"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte("{\"hello\": \"world\"}"))
})
pt := polling.Default
wt := websocket.Default
wt.CheckOrigin = func(req *http.Request) bool {
return true
}
server, err := socketio.NewServer(&engineio.Options{
Transports: []transport.Transport{
pt,
wt,
},
})
if err != nil {
log.Fatal(err)
}
server.OnConnect("/", func(s socketio.Conn) error {
s.SetContext("")
fmt.Println("connected:", s.ID())
return nil
})
server.OnEvent("/", "notice", func(s socketio.Conn, msg string) {
fmt.Println("notice:", msg)
s.Emit("reply", "have "+msg)
})
server.OnEvent("/chat", "msg", func(s socketio.Conn, msg string) string {
s.SetContext(msg)
return "recv " + msg
})
server.OnEvent("/", "bye", func(s socketio.Conn) string {
last := s.Context().(string)
s.Emit("bye", last)
s.Close()
return last
})
server.OnError("/", func(e error) {
fmt.Println("meet error:", e)
})
server.OnDisconnect("/", func(s socketio.Conn, msg string) {
fmt.Println("closed", msg)
})
go server.Serve()
defer server.Close()
mux.Handle("/socket.io/", server)
//http.Handle("/", http.FileServer(http.Dir("./asset")))
c := cors.New(cors.Options{
AllowedOrigins: []string{"http://localhost"},
AllowedMethods: []string{"GET", "PUT", "OPTIONS", "POST", "DELETE"},
AllowCredentials: true,
})
// decorate existing handler with cors functionality set in c
handler := c.Handler(mux)
log.Println("Serving at localhost:8000...")
log.Fatal(http.ListenAndServe(":8000", handler))
}
index.html i use official demo
Given that the CORS problem arises commonly when testing I found a workaround that is not perfect but it's only for testing.
What I did was I add middleware to remove any CORS problem
func (s *SocketIOService) SocketIOFix(w http.ResponseWriter, r *http.Request) {
// SocketIOService hold a variable called Server that is a *socketio.Server
// Remove or add everything for CORS
// This take care of the client
allowHeaders := "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization"
if origin := r.Header.Get("Origin"); origin != "" {
w.Header().Set("Access-Control-Allow-Origin", origin)
w.Header().Set("Vary", "Origin")
w.Header().Set("Access-Control-Allow-Methods", "POST, PUT, PATCH, GET, DELETE")
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Allow-Headers", allowHeaders)
}
if r.Method == "OPTIONS" {
return
}
// this takes care of the server side, No Orign no CORS baby
r.Header.Del("Origin")
// Return to Socket io
s.Server.ServeHTTP(w,r)
}
Here is another example:
func corsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
allowHeaders := "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization"
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "http://localhost:8100")
w.Header().Set("Access-Control-Allow-Methods", "POST, PUT, PATCH, GET, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Allow-Headers", allowHeaders)
next.ServeHTTP(w, r)
})
}
func main() {
server, err := socketio.NewServer(nil)
if err != nil {
log.Fatal(err)
}
controllers.RegisterSocketHandlers(server)
go server.Serve()
defer server.Close()
http.Handle("/socket.io/", corsMiddleware(server))
log.Println("Serving at localhost:3000...")
log.Fatal(http.ListenAndServe(":3000", nil))
}
Note: I was testing locally from my browser on http://localhost:8100 make sure to update this to the clients address that your testing against such as - http://localhost:8080 or http://mywebsite.com etc.
this code save my 1 day of frustation, please put this in the documentation.
thanks to your issue, it really helps me a lot @nick-bai
Thanks, it was a good starting point.
@nick-bai You are right! Thanks for your code! And the client javascript code is below: var socket = io('ws://127.0.0.1:8000', {transports: ['websocket']});
@isky0824 why polling is not working with this sample?
@LucasBadico I am very sorry that I don't know. But it works correctly on my computer.
Thanks for saving me, 2 days frustrated with this, even though I was always recommended to use gorilla websockets, I kept fooling around until socket.io works, again thanks (sorry for bas english, deepdl)
I found some problems,When I used this class library.My web page and socket service are not in the same domain,so it leads to the CORS problem. i try to solve CORS problem,but i cant not find any documentation. then I search in issues and find some useful code.finally solved it. To help more people solve the same problem, I'm going to share my code.
use branch 1.4 and socket-io.js 1.4 main.go
package main import ( "fmt" "log" "net/http" socketio "github.com/googollee/go-socket.io" "github.com/rs/cors" "github.com/googollee/go-engine.io/transport/polling" "github.com/googollee/go-engine.io/transport/websocket" "github.com/googollee/go-engine.io" "github.com/googollee/go-engine.io/transport" ) func main() { mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte("{\"hello\": \"world\"}")) }) pt := polling.Default wt := websocket.Default wt.CheckOrigin = func(req *http.Request) bool { return true } server, err := socketio.NewServer(&engineio.Options{ Transports: []transport.Transport{ pt, wt, }, }) if err != nil { log.Fatal(err) } server.OnConnect("/", func(s socketio.Conn) error { s.SetContext("") fmt.Println("connected:", s.ID()) return nil }) server.OnEvent("/", "notice", func(s socketio.Conn, msg string) { fmt.Println("notice:", msg) s.Emit("reply", "have "+msg) }) server.OnEvent("/chat", "msg", func(s socketio.Conn, msg string) string { s.SetContext(msg) return "recv " + msg }) server.OnEvent("/", "bye", func(s socketio.Conn) string { last := s.Context().(string) s.Emit("bye", last) s.Close() return last }) server.OnError("/", func(e error) { fmt.Println("meet error:", e) }) server.OnDisconnect("/", func(s socketio.Conn, msg string) { fmt.Println("closed", msg) }) go server.Serve() defer server.Close() mux.Handle("/socket.io/", server) //http.Handle("/", http.FileServer(http.Dir("./asset"))) c := cors.New(cors.Options{ AllowedOrigins: []string{"http://localhost"}, AllowedMethods: []string{"GET", "PUT", "OPTIONS", "POST", "DELETE"}, AllowCredentials: true, }) // decorate existing handler with cors functionality set in c handler := c.Handler(mux) log.Println("Serving at localhost:8000...") log.Fatal(http.ListenAndServe(":8000", handler)) }index.html i use official demo
ths,it help me
Given that the CORS problem arises commonly when testing I found a workaround that is not perfect but it's only for testing.
What I did was I add middleware to remove any CORS problem
func (s *SocketIOService) SocketIOFix(w http.ResponseWriter, r *http.Request) { // SocketIOService hold a variable called Server that is a *socketio.Server // Remove or add everything for CORS // This take care of the client allowHeaders := "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization" if origin := r.Header.Get("Origin"); origin != "" { w.Header().Set("Access-Control-Allow-Origin", origin) w.Header().Set("Vary", "Origin") w.Header().Set("Access-Control-Allow-Methods", "POST, PUT, PATCH, GET, DELETE") w.Header().Set("Access-Control-Allow-Credentials", "true") w.Header().Set("Access-Control-Allow-Headers", allowHeaders) } if r.Method == "OPTIONS" { return } // this takes care of the server side, No Orign no CORS baby r.Header.Del("Origin") // Return to Socket io s.Server.ServeHTTP(w,r) }
Very helpful!
I had the same problem. with tip [GIN-debug] [WARNING] Headers were already written. Wanted to override status code 403 with 502
In the project examples, I found the correct solution for CORS.
https://github.com/googollee/go-socket.io/blob/master/_examples/gin-cors/main.go