Làm thế nào để xây dựng một URI WebSocket liên quan đến URI trang?


95

Tôi muốn tạo một URI WebSocket liên quan đến URI trang ở phía trình duyệt. Giả sử, trong trường hợp của tôi, hãy chuyển đổi các URI HTTP như

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

đến

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

Những gì tôi đang làm hiện tại là thay thế 4 chữ cái đầu tiên "http" bằng "ws" và nối "/ to / ws" vào nó. Có cách nào tốt hơn cho điều đó không?


1
Ý bạn là path/to/wsgì Điều này dẫn chính xác đến đâu? Cảm ơn
slvin

Câu trả lời:


96

Nếu máy chủ Web của bạn có hỗ trợ WebSockets (hoặc một mô-đun xử lý WebSocket) thì bạn có thể sử dụng cùng một máy chủ và cổng và chỉ cần thay đổi sơ đồ như bạn đang hiển thị. Có nhiều tùy chọn để chạy máy chủ Web và máy chủ / mô-đun Websocket cùng nhau.

Tôi khuyên bạn nên xem xét từng phần riêng lẻ của window.location global và nối chúng lại với nhau thay vì thực hiện thay thế chuỗi mù.

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

Lưu ý rằng một số máy chủ web (tức là máy chủ dựa trên Jetty) hiện đang sử dụng đường dẫn (thay vì tiêu đề nâng cấp) để xác định xem một yêu cầu cụ thể có nên được chuyển đến trình xử lý WebSocket hay không. Vì vậy, bạn có thể bị hạn chế về việc bạn có thể biến đổi con đường theo cách bạn muốn hay không.


Sử dụng tên đường dẫn, tôi nhận được url như vậy: 'ws: // localhost: 8080 / Chat / index.html / chat'. Và đó là url không xuất huyết.
Denis535

1
@ wishmaster35 việc xử lý như thế nào sẽ tùy thuộc vào trường hợp sử dụng và thiết lập của bạn. Không có cách nào chắc chắn để xác định xem example.com/part1/part2 đề cập đến một tệp có tên part2 trong thư mục có tên là part1, hay wether part2 là một thư mục trong part1 hay một cái gì đó hoàn toàn khác (ví dụ: part1 và part2 là các khóa bên trong một cơ sở dữ liệu đối tượng). Ý nghĩa của "đường dẫn" trong URL tùy thuộc vào máy chủ web và cấu hình của nó. Bạn có thể suy ra rằng bất kỳ thứ gì kết thúc bằng "* .html" nên bị loại bỏ. Nhưng một lần nữa, điều này sẽ phụ thuộc vào thiết lập và yêu cầu cụ thể của bạn.
kanaka

3
@socketpair không, cổng ở đó. window.location.host chứa tên máy chủ và cổng (location.hostname chỉ là tên máy chủ).
kanaka

Tôi có thể bỏ đi "/to/ws"không? Nếu không, giá trị của phần đó phải là bao nhiêu?
tet

1
@tet đó là đường dẫn yêu cầu GET (tức là đường dẫn HTTP GET) được sử dụng khi kết nối WebSocket ban đầu được thiết lập. Nó có được sử dụng hay không tùy thuộc vào thiết lập của bạn. Nếu bạn có một máy chủ websocket mục đích duy nhất (có thể xảy ra cũng phục vụ các tệp web tĩnh) thì nó có thể bị bỏ qua. Nếu bạn có nhiều máy chủ websocket phía sau một máy chủ web chuyên dụng, thì đường dẫn có thể đang được sử dụng để định tuyến đến máy chủ websocket bên phải. Con đường cũng có thể được sử dụng cho các mục đích khác do máy chủ WebSocket như qua thẻ (ví dụ như thông qua truy vấn params) vv
Kanaka

32

Đây là phiên bản của tôi có thêm cổng tcp trong trường hợp nó không phải là 80 hoặc 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;
}

Chỉnh sửa 1: Phiên bản cải tiến theo đề xuất của @kanaka:

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

Chỉnh sửa 2: Ngày nay tôi tạo ra cái WebSocketnày:

var s = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/ws");

14
Bạn không cần phải làm cổng mangling, chỉ cần sử dụng location.host thay vì location.hostname
Kanaka

24

Sử dụng API Window.URL - https://developer.mozilla.org/en-US/docs/Web/API/Window/URL

Hoạt động với (các) http, cổng, v.v.

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

Tôi nên đề cập đến rằng điều này cũng làm việc với https / WSS (thay thế 'http' với 'ws' => 'https' => 'WSS')
Eadz

7

Giả sử máy chủ WebSocket của bạn đang nghe trên cùng một cổng mà từ đó trang đang được yêu cầu, tôi sẽ đề xuất:

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

Sau đó, đối với trường hợp của bạn, hãy gọi nó như sau:

var socket = createWebSocket(location.pathname + '/to/ws');

location.path không đúng. Bạn nên sử dụng tên đường dẫn.
Denis535

@ wishmaster35: Bắt tốt! Đã sửa.
Pavel

4

dễ dàng:

location.href.replace(/^http/, 'ws') + '/to/ws'
// or if you hate regexp:
location.href.replace('http://', 'ws://').replace('https://', 'wss://') + '/to/ws'

Tôi sẽ sử dụng /^http/thay vì 'http'chỉ trong trường hợp httpbên trong thanh URL.
phk

window.location.href bao gồm đường dẫn đầy đủ, vì vậy bạn có thể kết thúc /page.html/path/to/ws
Eadz

Có thể có vấn đề nếu vị trí của bạn chứa http. Ví dụ: testhttp.com/http.html
Dániel Kis

1
Chỉ cần thay thế 'http: //' với 'ws: //' rằng ý tưởng đơn giản nên được rõ ràng đối với bất kỳ nhà phát triển, thậm chí hậu bối
Maksim Kostromin

2

Trên localhost, bạn nên xem xét đường dẫn ngữ cảnh.

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
đường dẫn ngữ cảnh là gì?
amirouche

1

Trong bảng chữ:

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

Sử dụng:

alert(WebsocketUtils.websocketUrlByPath("/websocket"));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.