Come costruire un URI WebSocket relativo all'URI della pagina?


92

Voglio costruire un URI WebSocket relativo all'URI della pagina sul lato del browser. Dì, nel mio caso converti gli URI HTTP come

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

per

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

Quello che sto facendo attualmente è sostituire le prime 4 lettere "http" con "ws" e aggiungere "/ a / ws". C'è un modo migliore per farlo?


1
Cosa intendi con path/to/ws? Dove porta esattamente questo? Grazie
slevin

Risposte:


95

Se il tuo server Web ha il supporto per WebSocket (o un modulo gestore WebSocket), puoi usare lo stesso host e la stessa porta e cambiare semplicemente lo schema come stai mostrando. Ci sono molte opzioni per eseguire insieme un server Web e un server / modulo Websocket.

Suggerirei di guardare i singoli pezzi di window.location global e unirli di nuovo insieme invece di eseguire la sostituzione cieca delle stringhe.

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";

Si noti che alcuni server Web (ad esempio quelli basati su Jetty) attualmente utilizzano il percorso (anziché l'intestazione di aggiornamento) per determinare se una richiesta specifica deve essere trasmessa al gestore WebSocket. Quindi potresti essere limitato nella possibilità di trasformare il percorso nel modo che desideri.


Usando il nome del percorso ottengo tale URL: "ws: // localhost: 8080 / Chat / index.html / chat". Ed è un URL non corretto.
Denis535

1
@ wishmaster35 come viene gestito dipenderà dal tuo caso d'uso e dalla configurazione. Non esiste un modo sicuro per determinare se example.com/part1/part2 si riferisce a un file chiamato part2 all'interno di una directory chiamata part1, o se part2 è una directory all'interno di part1 o qualcosa di completamente diverso (ad esempio part1 e part2 sono chiavi all'interno un database di oggetti). Il significato di "percorsi" in un URL dipende dal server web e dalla sua configurazione. Si potrebbe dedurre che tutto ciò che termina con "* .html" dovrebbe essere rimosso. Ma ancora una volta, questo dipenderà dalla configurazione e dai requisiti specifici.
kanaka

3
@socketpair no, la porta è lì. window.location.host contiene il nome host e la porta (location.hostname è solo il nome host).
kanaka

Posso lasciare fuori "/to/ws"? In caso contrario, quale dovrebbe essere il valore per quella parte?
tet

1
@tet è il percorso della richiesta GET (ovvero il percorso HTTP GET) utilizzato quando viene stabilita la connessione WebSocket iniziale. Che venga utilizzato o meno dipende dalla configurazione. Se si dispone di un server Websocket a scopo singolo (che può accadere che serva anche file Web statici), probabilmente viene ignorato. Se si dispone di più server Websocket dietro un server Web dedicato, è probabile che il percorso venga utilizzato per instradare al server Websocket corretto. Il percorso può essere utilizzato anche per altri scopi dal server websocket come il passaggio di token (ad esempio tramite parametri di query), ecc.
kanaka

32

Ecco la mia versione che aggiunge la porta tcp nel caso in cui non sia 80 o 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;
}

Modifica 1: versione migliorata su suggerimento di @kanaka:

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

Modifica 2: Al giorno d'oggi creo WebSocketquesto:

var s = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/ws");

14
Non è necessario modificare le porte, basta usare location.host invece di location.hostname
kanaka

24

Utilizzo dell'API Window.URL - https://developer.mozilla.org/en-US/docs/Web/API/Window/URL

Funziona con http (s), porte ecc.

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

Devo dire che funziona anche con https / wss (sostituire 'http' con 'ws' => 'https' => 'wss')
Eadz

7

Supponendo che il tuo server WebSocket sia in ascolto sulla stessa porta da cui viene richiesta la pagina, suggerirei:

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

Quindi, per il tuo caso, chiamalo come segue:

var socket = createWebSocket(location.pathname + '/to/ws');

location.path non è corretto. Dovresti usare il nome del percorso.
Denis535

@ wishmaster35: buona cattura! Fisso.
Pavel

4

facile:

location.href.replace(/^http/, 'ws') + '/to/ws'
// or if you hate regexp:
location.href.replace('http://', 'ws://').replace('https://', 'wss://') + '/to/ws'

Lo userei al /^http/posto di 'http'solo nel caso httpsia all'interno della barra degli indirizzi.
phk

window.location.href include il percorso completo, quindi potresti finire /page.html/path/to/ws
Eadz

Può essere problematico se la tua posizione contiene http. Ad esempio: testhttp.com/http.html
Dániel Kis

1
Basta sostituire "http: //" con "ws: //" che la semplice idea dovrebbe essere ovvia a tutti gli sviluppatori, anche ai giovani
Maksim Kostromin

2

Su localhost dovresti considerare il percorso del contesto.

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;
}

4
qual è il percorso di contesto?
amirouche

1

In dattiloscritto:

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 "";
        }
    }
}

Utilizzo:

alert(WebsocketUtils.websocketUrlByPath("/websocket"));
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.