Як побудувати URI WebSocket щодо URI сторінки?


95

Я хочу створити 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

Відповіді:


96

Якщо ваш веб-сервер підтримує WebSockets (або модуль обробника WebSocket), ви можете використовувати той самий хост і порт і просто змінити схему, як показано. Існує багато варіантів спільного використання веб-сервера та сервера / модуля Websocket.

Я б запропонував вам подивитися на окремі фрагменти вікна.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", слід видалити. Але знову ж таки, це буде залежати від конкретних налаштувань та вимог.
канака

3
@socketpair ні, порт є. window.location.host містить ім'я хосту та порт (location.hostname - це лише ім'я хосту).
канака

Можна залишити "/to/ws"? Якщо ні, яке значення має ця частина?
тет

1
@tet - це шлях запиту GET (тобто шлях HTTP GET), який використовується, коли встановлено початкове з'єднання WebSocket. Чи буде він використовуватися чи ні, залежить від вашого налаштування. Якщо у вас є єдиний веб-сервер веб-розетки (який може також обслуговувати статичні веб-файли), він, ймовірно, ігнорується. Якщо за виділеним веб-сервером у вас кілька серверів websocket, то шлях, ймовірно, використовується для маршрутизації до правого сервера websocket. Шлях також може бути використаний веб-сервером для інших цілей, таких як передача токенів (наприклад, через параметри запиту) тощо
kanaka

32

Ось моя версія, яка додає порт 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
канака

24

Використання API Window.URL - https://developer.mozilla.org/en-US/docs/Web/API/Window/URL

Працює з http (и), портами тощо.

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знаходитись всередині рядка URL.
phk

window.location.href включає повний шлях, щоб ви могли закінчити
/page.html/path/to/ws

Це може бути проблематично, якщо ваше місцезнаходження містить 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;
}

4
що таке контекстний шлях?
amirouche

1

На машинописі:

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"));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.