120

I want to construct a WebSocket URI relative to the page URI at the browser side. Say, in my case convert HTTP URIs like

http://example.com:8000/path
https://example.com:8000/path

to

ws://example.com:8000/path/to/ws
wss://example.com:8000/path/to/ws

What I'm doing currently is replace the first 4 letters "http" by "ws", and append "/to/ws" to it. Is there any better way for that?

neuront
  • 9,312
  • 5
  • 42
  • 71

9 Answers9

122

If your Web server has support for WebSockets (or a WebSocket handler module) then you can use the same host and port and just change the scheme like you are showing. There are many options for running a Web server and Websocket server/module together.

I would suggest that you look at the individual pieces of the window.location global and join them back together instead of doing blind string substitution.

var loc = window.location, new_uri;
if (loc.protocol === "https:") {
    new_uri = "wss:";
} else {
    new_uri = "ws:";
}
new_uri += "//" + loc.host;
new_uri += loc.pathname + "/to/ws";

Note that some web servers (i.e. Jetty based ones) currently use the path (rather than the upgrade header) to determine whether a specific request should be passed on to the WebSocket handler. So you may be limited in whether you can transform the path in the way you want.

OKEE
  • 450
  • 3
  • 15
kanaka
  • 70,845
  • 23
  • 144
  • 140
  • 1
    Using pathname I get such url: 'ws://localhost:8080/Chat/index.html/chat'. And it's uncorrct url. – Denis535 Oct 24 '15 at 17:10
  • 1
    @wishmaster35 how that is handled is going to depend on your use case and setup. There is no sure-fire way to determine if http://example.com/part1/part2 refers to a file named part2 within a directory called part1, or wether part2 is a directory within part1, or something completely different (e.g. part1 and part2 are keys within a object database). The meaning of "paths" in a URL is up to the web server and its configuration. You could infer that anything ending in "*.html" should be stripped off. But again, this will depend on your specific setup and requirements. – kanaka Oct 25 '15 at 20:34
  • 3
    @socketpair no, port is there. window.location.host contains the hostname and the port (location.hostname is the hostname only). – kanaka Oct 28 '15 at 15:19
  • Can I leave out `"/to/ws"`? If not, what should be the value for that part? – tet Apr 11 '17 at 20:00
  • 1
    @tet that's the GET request path (i.e. the HTTP GET path) used when the initial WebSocket connection is established. Whether it is used or not depends on your setup. If you have a single purpose websocket server (that may happen to also serve static web files) then it is probably ignored. If you have multiple websocket servers behind a dedicated web server, then the path is probably being used to route to the right websocket server. The path can also be used for other purposes by the websocket server such as passing tokens (e.g. via query params), etc. – kanaka Apr 11 '17 at 20:54
48

Here is my version which adds the tcp port in case it's not 80 or 443:

function url(s) {
    var l = window.location;
    return ((l.protocol === "https:") ? "wss://" : "ws://") + l.hostname + (((l.port != 80) && (l.port != 443)) ? ":" + l.port : "") + l.pathname + s;
}

Edit 1: Improved version as by suggestion of @kanaka :

function url(s) {
    var l = window.location;
    return ((l.protocol === "https:") ? "wss://" : "ws://") + l.host + l.pathname + s;
}

Edit 2: Nowadays I create the WebSocket this:

var s = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/ws");
TmTron
  • 17,012
  • 10
  • 94
  • 142
yglodt
  • 13,807
  • 14
  • 91
  • 127
39

Using the Window.URL API - https://developer.mozilla.org/en-US/docs/Web/API/Window/URL

Works with http(s), ports etc.

var url = new URL('/path/to/websocket', window.location.href);

url.protocol = url.protocol.replace('http', 'ws');

url.href // => ws://www.example.com:9999/path/to/websocket
Eadz
  • 1,363
  • 13
  • 12
  • 1
    I should mention that this also works with https/wss ( replace 'http' with 'ws' => 'https' => 'wss' ) – Eadz Oct 31 '19 at 09:15
9

Assuming your WebSocket server is listening on the same port as from which the page is being requested, I would suggest:

function createWebSocket(path) {
    var protocolPrefix = (window.location.protocol === 'https:') ? 'wss:' : 'ws:';
    return new WebSocket(protocolPrefix + '//' + location.host + path);
}

Then, for your case, call it as follows:

var socket = createWebSocket(location.pathname + '/to/ws');
Pavel
  • 5,320
  • 8
  • 35
  • 45
6

easy:

location.href.replace(/^http/, 'ws') + '/to/ws'
// or if you hate regexp:
location.href.replace('http://', 'ws://').replace('https://', 'wss://') + '/to/ws'
Maksim Kostromin
  • 3,273
  • 1
  • 32
  • 30
2

On localhost you should consider context path.

function wsURL(path) {
    var protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://';
    var url = protocol + location.host;
    if(location.hostname === 'localhost') {
        url += '/' + location.pathname.split('/')[1]; // add context path
    }
    return url + path;
}
Alexis Tyler
  • 1,394
  • 6
  • 30
  • 48
Denis535
  • 3,407
  • 4
  • 25
  • 36
2

In typescript:

export class WebsocketUtils {

    public static websocketUrlByPath(path) {
        return this.websocketProtocolByLocation() +
            window.location.hostname +
            this.websocketPortWithColonByLocation() +
            window.location.pathname +
            path;
    }

    private static websocketProtocolByLocation() {
        return window.location.protocol === "https:" ? "wss://" : "ws://";
    }

    private static websocketPortWithColonByLocation() {
        const defaultPort = window.location.protocol === "https:" ? "443" : "80";
        if (window.location.port !== defaultPort) {
            return ":" + window.location.port;
        } else {
            return "";
        }
    }
}

Usage:

alert(WebsocketUtils.websocketUrlByPath("/websocket"));
Dániel Kis
  • 2,341
  • 5
  • 28
  • 51
1

I agree with @Eadz, something like this is cleaner and safer:

const url = new URL('./ws', location.href);
url.protocol = url.protocol.replace('http', 'ws');
const webSocket = new WebSocket(url);

The URL class saves work and deals with things like query parameters, etc.

-1

Dead easy solution, ws and port, tested:

var ws = new WebSocket("ws://" + window.location.host + ":6666");

ws.onopen = function() { ws.send( .. etc
Fattie
  • 27,874
  • 70
  • 431
  • 719