Как создать URI WebSocket относительно URI страницы?

96

Я хочу создать URI WebSocket относительно URI страницы на стороне браузера. Скажем, в моем случае конвертировать HTTP URI, например

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

к

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

Сейчас я заменяю первые 4 буквы «http» на «ws» и добавляю к ним «/ to / ws». Есть ли лучший способ для этого?

нейрон
источник
1
Что вы имеете в виду path/to/ws? Куда именно это ведет? Спасибо
slevin
"ws: //" + window.location.host + ": 6666" -done
Fattie

Ответы:

99

Если ваш веб-сервер поддерживает WebSockets (или модуль обработчика WebSocket), вы можете использовать тот же хост и порт и просто изменить схему, как вы показываете. Существует множество вариантов совместной работы веб-сервера и сервера / модуля Websocket.

Я бы посоветовал вам взглянуть на отдельные части глобального окна window.location и снова соединить их вместе, вместо того, чтобы выполнять слепую подстановку строк.

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

Обратите внимание, что некоторые веб-серверы (например, на базе Jetty) в настоящее время используют путь (а не заголовок обновления), чтобы определить, следует ли передать конкретный запрос обработчику WebSocket. Таким образом, вы можете быть ограничены в том, можете ли вы преобразовать путь так, как хотите.

канака
источник
Используя имя пути, я получаю такой URL: 'ws: // localhost: 8080 / Chat / index.html / chat'. И это неверный URL.
Denis535
1
@ wishmaster35, как это будет обрабатываться, будет зависеть от вашего варианта использования и настроек. Нет надежного способа определить, относится ли example.com/part1/part2 к файлу с именем part2 в каталоге с именем part1, или является ли part2 каталогом внутри part1 или чем-то совершенно другим (например, part1 и part2 являются ключами внутри объектная база данных). Значение «путей» в URL зависит от веб-сервера и его конфигурации. Вы можете сделать вывод, что все, что заканчивается на «* .html», следует удалить. Но опять же, это будет зависеть от ваших конкретных настроек и требований.
kanaka
3
@socketpair нет, порт есть. window.location.host содержит имя хоста и порт (location.hostname - это только имя хоста).
kanaka
Могу я уйти "/to/ws"? Если нет, то какой должна быть ценность для этой части?
тет
1
@tet - это путь запроса GET (т. е. путь HTTP GET), используемый при установке начального соединения WebSocket. Используется он или нет, зависит от вашей настройки. Если у вас есть одноцелевой сервер websocket (который может также обслуживать статические веб-файлы), он, вероятно, игнорируется. Если у вас есть несколько серверов веб-сокетов за выделенным веб-сервером, то путь, вероятно, используется для маршрутизации к нужному серверу веб-сокетов. Путь также может быть использован для других целей сервера WebSocket , таких как маркера прохождения (например , с помощью запроса PARAMS) и т.д.
канак
33

Вот моя версия, которая добавляет порт tcp, если это не 80 или 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;
}

Изменить 1: улучшенная версия по предложению @kanaka:

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

Изменить 2: В настоящее время я создаю WebSocketэто:

var s = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/ws");
Иглодт
источник
14
Вам не нужно изменять порт, просто используйте location.host вместо location.hostname
kanaka
25

Использование API Window.URL - https://developer.mozilla.org/en-US/docs/Web/API/Window/URL

Работает с http (s), портами и т. Д.

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
Эдз
источник
Я должен упомянуть, что это также работает с https / wss (замените 'http' на 'ws' => 'https' => 'wss')
Eadz
7

Предполагая, что ваш сервер WebSocket прослушивает тот же порт, с которого запрашивается страница, я бы предложил:

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

Затем для вашего случая назовите его следующим образом:

var socket = createWebSocket(location.pathname + '/to/ws');
Павел
источник
location.path неверен. Вы должны использовать путь.
Denis535
@ wishmaster35: Хороший улов! Исправлена.
Павел
4

легко:

location.href.replace(/^http/, 'ws') + '/to/ws'
// or if you hate regexp:
location.href.replace('http://', 'ws://').replace('https://', 'wss://') + '/to/ws'
Максим Костромин
источник
Я бы использовал /^http/вместо этого на 'http'всякий случай httpвнутри адресной строки.
phk
window.location.href включает полный путь, так что вы можете закончить /page.html/path/to/ws
Eadz
Может быть проблематично, если ваше местоположение содержит http. Например: testhttp.com/http.html
Даниэль Кис
1
Просто замените http: // на ws: // - эта простая идея должна быть очевидна для любого разработчика, даже для юниоров,
Максим Костромин
2

На localhost вы должны учитывать контекстный путь.

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;
}
Денис535
источник
4
что такое контекстный путь?
amirouche
2

В машинописном тексте:

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

Применение:

alert(WebsocketUtils.websocketUrlByPath("/websocket"));
Даниэль Кис
источник
0

Мертвое простое решение, ws и порт, протестировано:

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

ws.onopen = function() { ws.send( .. etc
Толстяк
источник