Jak utworzyć identyfikator URI protokołu WebSocket względem identyfikatora URI strony?

96

Chcę utworzyć identyfikator URI protokołu WebSocket względem identyfikatora URI strony po stronie przeglądarki. Powiedzmy, w moim przypadku przekonwertuj identyfikatory URI HTTP, takie jak

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

do

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

Obecnie zamieniam pierwsze 4 litery „http” na „ws” i dopisuję do niego „/ do / ws”. Czy jest na to lepszy sposób?

neuront
źródło
1
Co masz na myśli path/to/ws? Dokąd to dokładnie prowadzi? Dzięki
slevin
"ws: //" + window.location.host + ": 6666" -done
Fattie

Odpowiedzi:

99

Jeśli twój serwer WWW obsługuje WebSockets (lub moduł obsługi WebSocket), możesz użyć tego samego hosta i portu i po prostu zmienić schemat, jak pokazano. Istnieje wiele możliwości jednoczesnego uruchamiania serwera WWW i serwera / modułu Websocket.

Sugerowałbym, abyś spojrzał na poszczególne elementy window.location global i złączył je z powrotem, zamiast wykonywać zastępowanie ślepych łańcuchów.

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

Zauważ, że niektóre serwery WWW (np. Te oparte na Jetty) używają obecnie ścieżki (zamiast nagłówka aktualizacji) do określenia, czy określone żądanie powinno zostać przekazane do programu obsługi WebSocket. Więc możesz być ograniczony w tym, czy możesz zmienić ścieżkę w sposób, w jaki chcesz.

kanaka
źródło
Korzystając ze ścieżki otrzymuję taki adres URL: „ws: // localhost: 8080 / Chat / index.html / chat”. I to nieskorygowany adres URL.
Denis535
1
@ Wishmaster35, jak to zostanie obsłużone, będzie zależeć od twojego przypadku użycia i konfiguracji. Nie ma pewnego sposobu na ustalenie, czy przykład.com/ part1/part2 odnosi się do pliku o nazwie część2 w katalogu o nazwie część1, czy też część2 to katalog w części1, czy też coś zupełnie innego (np. Część1 i część2 to klucze w obrębie obiektowa baza danych). Znaczenie „ścieżek” w adresie URL zależy od serwera WWW i jego konfiguracji. Można wywnioskować, że wszystko, co kończy się na „* .html”, powinno zostać usunięte. Ale znowu będzie to zależeć od twojej konkretnej konfiguracji i wymagań.
kanaka
3
@socketpair nie, port jest dostępny. window.location.host zawiera nazwę hosta i port (lokalizacja.nazwa hosta to tylko nazwa hosta).
kanaka
Czy mogę wyjść "/to/ws"? Jeśli nie, jaka powinna być wartość tej części?
tet
1
@tet to ścieżka żądania GET (tj. ścieżka HTTP GET) używana podczas ustanawiania początkowego połączenia WebSocket. To, czy jest używany, czy nie, zależy od konfiguracji. Jeśli masz serwer WebSocket o jednym przeznaczeniu (który może również obsługiwać statyczne pliki internetowe), prawdopodobnie jest on ignorowany. Jeśli masz wiele serwerów WebSocket za dedykowanym serwerem internetowym, prawdopodobnie ścieżka jest używana do kierowania do właściwego serwera WebSocket. Ścieżka może być również używana do innych celów przez serwer websocket, takich jak przekazywanie tokenów (np. Poprzez parametry zapytania) itp.
kanaka Kwietnia
33

Oto moja wersja, która dodaje port TCP na wypadek, gdyby nie był to 80 lub 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;
}

Edycja 1: ulepszona wersja zgodnie z sugestią @kanaka:

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

Edycja 2: Obecnie tworzę WebSocketto:

var s = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/ws");
yglodt
źródło
14
Nie musisz zmieniać portów, po prostu użyj location.host zamiast location.hostname
kanaka
25

Korzystanie z interfejsu API Window.URL - https://developer.mozilla.org/en-US/docs/Web/API/Window/URL

Działa z http (s), portami itp.

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
źródło
Powinienem wspomnieć, że działa to również z https / wss (zamień „http” na „ws” => „https” => „wss”)
Eadz
7

Zakładając, że Twój serwer WebSocket nasłuchuje na tym samym porcie, z którego żądana jest strona, proponuję:

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

Następnie, w swoim przypadku, nazwij to w następujący sposób:

var socket = createWebSocket(location.pathname + '/to/ws');
Pavel
źródło
location.path jest nieprawidłowa. Powinieneś użyć nazwy ścieżki.
Denis535
@ wishmaster35: Dobry chwyt! Naprawiony.
Pavel
4

łatwy:

location.href.replace(/^http/, 'ws') + '/to/ws'
// or if you hate regexp:
location.href.replace('http://', 'ws://').replace('https://', 'wss://') + '/to/ws'
Maksim Kostromin
źródło
Użyłbym /^http/zamiast na 'http'wszelki wypadek httpwewnątrz paska adresu URL.
phk
window.location.href zawiera pełną ścieżkę, więc możesz skończyć na /page.html/path/to/ws
Eadz
Może to być problematyczne, jeśli Twoja lokalizacja zawiera http. Na przykład: testhttp.com/http.html
Dániel Kis
1
Po prostu zamień „http: //” na „ws: //” - ten prosty pomysł powinien być oczywisty dla wszystkich programistów, nawet dla juniorów
Maksim Kostromin,
2

Na hoście lokalnym powinieneś rozważyć ścieżkę kontekstu.

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
źródło
4
co to jest ścieżka kontekstu?
amirouche
2

Na maszynie:

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

Stosowanie:

alert(WebsocketUtils.websocketUrlByPath("/websocket"));
Dániel Kis
źródło
0

Dead easy rozwiązanie, WS i port, przetestowane:

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

ws.onopen = function() { ws.send( .. etc
Fattie
źródło