How to construct a WebSocket URI relative to the page URI?
Asked Answered
C

9

125

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?

Claustral answered 2/5, 2012 at 2:25 Comment(2)
What do you mean by path/to/ws? Where does this leads exactly? ThanksUnderfeed
"ws://" + window.location.host + ":6666" -donePyemia
C
124

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.

Chip answered 2/5, 2012 at 16:39 Comment(5)
Using pathname I get such url: 'ws://localhost:8080/Chat/index.html/chat'. And it's uncorrct url.Dinny
@wishmaster35 how that is handled is going to depend on your use case and setup. There is no sure-fire way to determine if 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.Chip
@socketpair no, port is there. window.location.host contains the hostname and the port (location.hostname is the hostname only).Chip
Can I leave out "/to/ws"? If not, what should be the value for that part?Veda
@Veda 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.Chip
M
52

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");
Mecke answered 23/11, 2013 at 11:6 Comment(1)
You don't need to do port mangling, just use location.host instead of location.hostnameChip
R
41

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
Rhodarhodamine answered 24/11, 2017 at 11:59 Comment(1)
I should mention that this also works with https/wss ( replace 'http' with 'ws' => 'https' => 'wss' )Rhodarhodamine
Z
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');
Zygapophysis answered 9/7, 2015 at 16:24 Comment(0)
E
7

easy:

location.href.replace(/^http/, 'ws') + '/to/ws'
// or if you hate regexp:
location.href.replace('http://', 'ws://').replace('https://', 'wss://') + '/to/ws'
Ecru answered 7/5, 2017 at 23:35 Comment(5)
I would use /^http/ instead of 'http' just in case http is inside the URL bar.Wyandotte
window.location.href includes the full path, so you could end up /page.html/path/to/wsRhodarhodamine
Can be problematic if your location contains http. For instance: testhttp.com/http.htmlCatherin
Just replace ‘http://‘ with ‘ws://‘ that simple idea should be obvious to any developers, even juniorsEcru
You may want to use the location.origin instead of location.href.Jenness
I
5

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.

Impinge answered 30/4, 2022 at 2:24 Comment(0)
D
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;
}
Dinny answered 25/10, 2015 at 18:30 Comment(1)
what is context path?Heartwarming
E
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"));
Evermore answered 2/12, 2017 at 17:51 Comment(0)
P
-1

Dead easy solution, ws and port, tested:

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

ws.onopen = function() { ws.send( .. etc
Pyemia answered 14/10, 2020 at 17:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.