Search code examples
javascriptgowebsocketgorilla

How the client can communicate with the WebSocket server from any domain name server like api


How to create a WebSocket server that any client from any domain-name/ip-address can communicate with. I don't want to have to open a page with a custom address provided by the server in order to communicate with the server.

The goal is to be able to communicate with the WebSocket server, through browser extensions, for example, or through any unexpected endpoint.

server.go

package main

import (
    "fmt"
    "net/http"

    "github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
}

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        conn, err := upgrader.Upgrade(w, r, nil) 
        if err != nil {
           fmt.Println(err) // no error just when websocket connecte from my domain
        }
        for {
            // Read message from browser
            msgType, msg, _ := conn.ReadMessage()

            // Print the message to the console
            fmt.Printf("%s sent: %s\n", conn.RemoteAddr(), string(msg))

            // Write message back to browser
            if err = conn.WriteMessage(msgType, msg); err != nil {
                return
            }
        }
    })

    http.HandleFunc("/client", func(w http.ResponseWriter, r *http.Request) { // I dont need this 
    http.ServeFile(w, r, "client.html")
  })

    http.ListenAndServe(":8080", nil)
}

client.js

<!DOCTYPE html>
<html>
    <head>
        <meta charset=utf8>
        <meta name=viewoirt content="width=device-width, initial-scale=1.0">
        <title>click bot</title>
        
    </head>
<body>
<input id="input" type="text" />
<button onclick="send()">Send</button>
<pre id="output"></pre>
<script>
    var input = document.getElementById("input");
    var output = document.getElementById("output");
    var socket = new WebSocket("ws://localhost:8080/");

    socket.onopen = function () {
        output.innerHTML += "Status: Connected\n";
    };

    socket.onmessage = function (e) {
        output.innerHTML += "Server: " + e.data + "\n";
    };

    function send() {
        socket.send(input.value);
        input.value = "";
    }
</script>
</body>
</html>

Everything is fine when I connecte through localhost:8080/client Either via the link or by injecting it through browser extensions. But when I inject it into another page that doesn't have the same ip address, it doesn't work. For example: For example, when I am typing in the console: websocket = new webSocket('ws://localhost: 8080') in a domain other than my domain.

CLIEnt ERRORE :

VM447:1 WebSocket connection to 'ws://localhost:8080/' failed: Connection closed before receiving a handshake response.

SERVER ERROR : websocket: request origin not allowed by Upgrader.CheckOrigin


Solution

  • For example, when I am typing in the console: websocket = new webSocket('ws://localhost: 8080') in a domain other than my domain.

    The server code in the question implements a same-origin policy. Change the check origin function to allow connections from any origin:

    var upgrader = websocket.Upgrader{
        ReadBufferSize:  1024,
        WriteBufferSize: 1024,
        CheckOrigin:  func(r *http.Request) bool { return true }
    }
    

    The question says that the server code ignores the error from upgrade for simplicity. If the server code had logged the error, the problem would have been immediately obvious. Always handle errors!

    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        fmt.Println(err)
        return
    }