Comment construire un URI WebSocket par rapport à l'URI de la page?

95

Je veux construire un URI WebSocket par rapport à l'URI de la page côté navigateur. Dites, dans mon cas, convertissez les URI HTTP comme

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

à

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

Ce que je fais actuellement, c'est remplacer les 4 premières lettres «http» par «ws», et y ajouter «/ to / ws». Y a-t-il un meilleur moyen pour cela?

neuront
la source
1
Que voulez-vous dire path/to/ws? Où cela mène-t-il exactement? Merci
slevin

Réponses:

96

Si votre serveur Web prend en charge WebSockets (ou un module de gestionnaire WebSocket), vous pouvez utiliser le même hôte et le même port et changer simplement le schéma comme vous le montrez. Il existe de nombreuses options pour exécuter ensemble un serveur Web et un serveur / module Websocket.

Je vous suggère de regarder les différentes parties du global window.location et de les réunir au lieu de faire une substitution de chaîne aveugle.

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

Notez que certains serveurs Web (c'est-à-dire ceux basés sur Jetty) utilisent actuellement le chemin (plutôt que l'en-tête de mise à niveau) pour déterminer si une requête spécifique doit être transmise au gestionnaire WebSocket. Vous pouvez donc être limité dans la possibilité de transformer le chemin comme vous le souhaitez.

Kanaka
la source
En utilisant le chemin d'accès, j'obtiens une telle URL: 'ws: // localhost: 8080 / Chat / index.html / chat'. Et c'est une URL non corrigée.
Denis535
1
@ wishmaster35 comment cela sera géré dépendra de votre cas d'utilisation et de votre configuration. Il n'y a pas de moyen sûr de déterminer si example.com/part1/part2 fait référence à un fichier nommé part2 dans un répertoire appelé part1, ou si part2 est un répertoire dans part1, ou quelque chose de complètement différent (par exemple part1 et part2 sont des clés dans une base de données d'objets). La signification des «chemins» dans une URL dépend du serveur Web et de sa configuration. Vous pouvez en déduire que tout ce qui se termine par "* .html" doit être supprimé. Mais encore une fois, cela dépendra de votre configuration et de vos exigences spécifiques.
kanaka
3
@socketpair non, le port est là. window.location.host contient le nom d'hôte et le port (location.hostname est le nom d'hôte uniquement).
kanaka
Puis-je laisser de côté "/to/ws"? Sinon, quelle devrait être la valeur de cette pièce?
tet le
1
@tet est le chemin de la requête GET (c'est-à-dire le chemin HTTP GET) utilisé lorsque la connexion WebSocket initiale est établie. Qu'il soit utilisé ou non dépend de votre configuration. Si vous avez un serveur Websocket à usage unique (qui peut également servir des fichiers Web statiques), il est probablement ignoré. Si vous avez plusieurs serveurs Websocket derrière un serveur Web dédié, le chemin est probablement utilisé pour acheminer vers le bon serveur Websocket. Le chemin peut également être utilisé à d'autres fins par le serveur websocket comme la transmission de jetons (par exemple via des paramètres de requête), etc.
kanaka
32

Voici ma version qui ajoute le port tcp au cas où ce ne serait pas 80 ou 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: Version améliorée comme par suggestion de @kanaka:

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

Edit 2: De nos jours, je crée le WebSocketceci:

var s = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/ws");
yglodt
la source
14
Vous n'avez pas besoin de modifier les ports, utilisez simplement location.host au lieu de location.hostname
kanaka
24

Utilisation de l'API Window.URL - https://developer.mozilla.org/en-US/docs/Web/API/Window/URL

Fonctionne avec 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
la source
Je dois mentionner que cela fonctionne également avec https / wss (remplacez 'http' par 'ws' => 'https' => 'wss')
Eadz
7

En supposant que votre serveur WebSocket écoute sur le même port que celui à partir duquel la page est demandée, je suggérerais:

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

Ensuite, pour votre cas, appelez-le comme suit:

var socket = createWebSocket(location.pathname + '/to/ws');
Pavel
la source
location.path n'est pas correct. Vous devez utiliser pathname.
Denis535
@ wishmaster35: Bonne prise! Fixé.
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'
Maksim Kostromin
la source
J'utiliserais /^http/au lieu de 'http'juste au cas où se httptrouve à l'intérieur de la barre d'URL.
phk
window.location.href inclut le chemin complet, vous pouvez donc terminer /page.html/path/to/ws
Eadz
Peut être problématique si votre emplacement contient http. Par exemple: testhttp.com/http.html
Dániel Kis
1
Remplacez simplement 'http: //' par 'ws: //' cette idée simple devrait être évidente pour tous les développeurs, même les juniors
Maksim Kostromin
2

Sur localhost, vous devez considérer le chemin de contexte.

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;
}
Denis535
la source
4
qu'est-ce que le chemin de contexte?
amirouche
1

En texte dactylographié:

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
la source