Bagaimana cara membuat URI WebSocket relatif terhadap URI halaman?

95

Saya ingin membuat URI WebSocket relatif terhadap URI halaman di sisi browser. Katakanlah, dalam kasus saya, ubah HTTP URI seperti

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

untuk

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

Yang saya lakukan sekarang adalah mengganti 4 huruf pertama "http" dengan "ws", dan menambahkan "/ to / ws" padanya. Apakah ada cara yang lebih baik untuk itu?

neuront
sumber
1
Apa yang Anda maksud dengan path/to/ws? Kemana tepatnya ini mengarah? Terima kasih
slevin

Jawaban:

96

Jika server Web Anda memiliki dukungan untuk WebSockets (atau modul handler WebSocket) maka Anda dapat menggunakan host dan port yang sama dan hanya mengubah skema seperti yang Anda tunjukkan. Ada banyak pilihan untuk menjalankan server Web dan server / modul Websocket secara bersamaan.

Saya menyarankan agar Anda melihat bagian individual window.location global dan menggabungkannya kembali daripada melakukan substitusi blind string.

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

Perhatikan bahwa beberapa server web (yaitu yang berbasis Jetty) saat ini menggunakan jalur (bukan header pemutakhiran) untuk menentukan apakah permintaan tertentu harus diteruskan ke penangan WebSocket. Jadi, Anda mungkin dibatasi dalam apakah Anda dapat mengubah jalan sesuai keinginan Anda.

kanaka
sumber
Menggunakan nama path saya mendapatkan url seperti: 'ws: // localhost: 8080 / Chat / index.html / chat'. Dan itu url tidak benar.
Denis535
1
@ wishmaster35 bagaimana hal itu ditangani akan bergantung pada kasus penggunaan dan pengaturan Anda. Tidak ada cara pasti untuk menentukan apakah example.com/part1/part2 merujuk ke file bernama part2 dalam direktori yang disebut part1, atau apakah part2 adalah direktori di dalam part1, atau sesuatu yang sama sekali berbeda (misalnya part1 dan part2 adalah kunci di dalamnya database objek). Arti "paths" di URL tergantung pada web server dan konfigurasinya. Anda dapat menyimpulkan bahwa apa pun yang diakhiri dengan "* .html" harus dihilangkan. Tetapi sekali lagi, ini akan tergantung pada pengaturan dan persyaratan spesifik Anda.
kanaka
3
@socketpair no, port ada di sana. window.location.host berisi nama host dan port (location.hostname adalah nama host saja).
kanaka
Bisakah saya keluar "/to/ws"? Jika tidak, berapa nilai yang seharusnya untuk bagian itu?
tet
1
@ set itulah jalur permintaan GET (yaitu jalur HTTP GET) yang digunakan ketika sambungan WebSocket awal dibuat. Apakah itu digunakan atau tidak tergantung pada pengaturan Anda. Jika Anda memiliki server websocket tujuan tunggal (yang mungkin juga melayani file web statis) maka mungkin akan diabaikan. Jika Anda memiliki beberapa server websocket di belakang server web khusus, maka jalur tersebut mungkin digunakan untuk merutekan ke server websocket yang tepat. Path juga dapat digunakan untuk tujuan lain oleh server websocket seperti meneruskan token (misalnya melalui query params), dll.
kanaka
32

Ini adalah versi saya yang menambahkan port tcp jika bukan 80 atau 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: Versi yang ditingkatkan sebagai saran dari @kanaka:

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

Edit 2: Saat ini saya membuat WebSocketini:

var s = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/ws");
yglodt
sumber
14
Anda tidak perlu melakukan port mangling, cukup gunakan location.host daripada location.hostname
kanaka
24

Menggunakan Window.URL API - https://developer.mozilla.org/en-US/docs/Web/API/Window/URL

Bekerja dengan http (s), port dll.

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
sumber
Saya harus menyebutkan bahwa ini juga berfungsi dengan https / wss (ganti 'http' dengan 'ws' => 'https' => 'wss')
Eadz
7

Dengan asumsi server WebSocket Anda mendengarkan pada port yang sama seperti dari mana halaman tersebut diminta, saya sarankan:

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

Kemudian, untuk kasus Anda, sebut sebagai berikut:

var socket = createWebSocket(location.pathname + '/to/ws');
Pavel
sumber
location.path salah. Anda harus menggunakan nama jalur.
Denis535
@ wishmaster35: Tangkapan bagus! Tetap.
Pavel
4

mudah:

location.href.replace(/^http/, 'ws') + '/to/ws'
// or if you hate regexp:
location.href.replace('http://', 'ws://').replace('https://', 'wss://') + '/to/ws'
Maksim Kostromin
sumber
Saya akan menggunakan /^http/alih-alih 'http'hanya jika httpada di dalam bilah URL.
phk
window.location.href menyertakan jalur lengkap, jadi Anda bisa berakhir di /page.html/path/to/ws
Eadz
Dapat menjadi masalah jika lokasi Anda berisi http. Misalnya: testhttp.com/http.html
Dániel Kis
1
Cukup ganti 'http: //' dengan 'ws: //' bahwa ide sederhana itu harus terlihat jelas bagi setiap pengembang, bahkan junior
Maksim Kostromin
2

Di localhost, Anda harus mempertimbangkan jalur konteks.

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
sumber
4
apa itu jalur konteks?
amirouche
2

Dalam naskah ketikan:

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

Pemakaian:

alert(WebsocketUtils.websocketUrlByPath("/websocket"));
Dániel Kis
sumber