如何构造一个相对于页面 URI 的 WebSocket URI?

我想在浏览器端构造一个相对于页面 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”附加到它。还有更好的办法吗?

132302 次浏览

如果您的 Web 服务器支持 WebSocket (或 WebSocket 处理程序模块) ,那么您可以使用相同的主机和端口,只需像您所显示的那样更改方案。有许多选项可以一起运行 Web 服务器和 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";

注意,一些 Web 服务器(即基于 Jetty 的服务器)目前使用路径(而不是升级头)来确定是否应该将特定请求传递给 WebSocket 处理程序。因此,你可能会受到限制,无论你是否可以改变你想要的方式的道路。

下面是我的版本,它添加了 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;
}

Edit 1: Improved version as by suggestion of @kanaka :

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

Edit 2: Nowadays I create the WebSocket this:

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

假设您的 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');

在本地主机上,应该考虑上下文路径。

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

简单:

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

使用 Window.URL API-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

打字稿:

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

绝对简单的解决方案,新闻和港口,测试:

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


ws.onopen = function() { ws.send( .. etc

我同意@Eadz 的看法,这样做更干净、更安全:

const url = new URL('./ws', location.href);
url.protocol = url.protocol.replace('http', 'ws');
const webSocket = new WebSocket(url);

URL类可以节省工作并处理诸如查询参数之类的事情。