Javascript Websockets 客户端 API 中的 HTTP 标头

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4361173/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 12:04:54  来源:igfitidea点击:

HTTP headers in Websockets client API

javascripthttpheaderwebsocket

提问by Julien Genestoux

Looks like it's easy to add custom HTTP headers to your websocket client with any HTTP header client which supports this, but I can't find how to do it with the JSON API.

看起来很容易使用任何支持此功能的 HTTP 标头客户端将自定义 HTTP 标头添加到您的 websocket 客户端,但我找不到如何使用 JSON API 来做到这一点。

Yet, it seems that there should be support these headers in the spec.

然而,似乎应该在规范中支持这些标头

Anyone has a clue on how to achieve it?

任何人都知道如何实现它?

var ws = new WebSocket("ws://example.com/service");

Specifically, I need to be able to send an HTTP Authorization header.

具体来说,我需要能够发送 HTTP 授权标头。

回答by kanaka

Updated 2x

更新 2 倍

Short answer: No, only the path and protocol field can be specified.

简短回答:不可以,只能指定路径和协议字段。

Longer answer:

更长的答案:

There is no method in the JavaScript WebSockets APIfor specifying additional headers for the client/browser to send. The HTTP path ("GET /xyz") and protocol header ("Sec-WebSocket-Protocol") can be specified in the WebSocket constructor.

JavaScript WebSockets API 中没有用于指定客户端/浏览器要发送的附加标头的方法。可以在 WebSocket 构造函数中指定 HTTP 路径(“GET /xyz”)和协议头(“Sec-WebSocket-Protocol”)。

The Sec-WebSocket-Protocol header (which is sometimes extended to be used in websocket specific authentication) is generated from the optional second argument to the WebSocket constructor:

Sec-WebSocket-Protocol 标头(有时会扩展以用于特定于 websocket 的身份验证)是从 WebSocket 构造函数的可选第二个参数生成的:

var ws = new WebSocket("ws://example.com/path", "protocol");
var ws = new WebSocket("ws://example.com/path", ["protocol1", "protocol2"]);

The above results in the following headers:

以上结果产生以下标题:

Sec-WebSocket-Protocol: protocol

and

Sec-WebSocket-Protocol: protocol1, protocol2

A common pattern for achieving WebSocket authentication/authorization is to implement a ticketing system where the page hosting the WebSocket client requests a ticket from the server and then passes this ticket during WebSocket connection setup either in the URL/query string, in the protocol field, or required as the first message after the connection is established. The server then only allows the connection to continue if the ticket is valid (exists, has not been already used, client IP encoded in ticket matches, timestamp in ticket is recent, etc). Here is a summary of WebSocket security information: https://devcenter.heroku.com/articles/websocket-security

实现 WebSocket 身份验证/授权的常见模式是实现票务系统,其中托管 WebSocket 客户端的页面从服务器请求票证,然后在 WebSocket 连接设置期间在 URL/查询字符串、协议字段中传递此票证,或作为连接建立后的第一条消息。然后,如果票证有效(存在、尚未使用、票证中编码的客户端 IP 匹配、票证中的时间戳是最近的等),服务器仅允许连接继续。以下是 WebSocket 安全信息的摘要:https: //devcenter.heroku.com/articles/websocket-security

Basic authentication was formerly an option but this has been deprecated and modern browsers don't send the header even if it is specified.

基本身份验证以前是一个选项,但这已被弃用,即使指定了标头,现代浏览器也不会发送标头。

Basic Auth Info (Deprecated):

基本身份验证信息(已弃用)

The Authorization header is generated from the username and password (or just username) field of the WebSocket URI:

Authorization 标头是从 WebSocket URI 的用户名和密码(或只是用户名)字段生成的:

var ws = new WebSocket("ws://username:[email protected]")

The above results in the following header with the string "username:password" base64 encoded:

上面的结果是带有字符串“username:password”base64 编码的以下标头:

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

I have tested basic auth in Chrome 55 and Firefox 50 and verified that the basic auth info is indeed negotiated with the server (this may not work in Safari).

我已经在 Chrome 55 和 Firefox 50 中测试了基本身份验证,并验证了基本身份验证信息确实是与服务器协商的(这在 Safari 中可能不起作用)。

Thanks to Dmitry Frank's for the basic auth answer

感谢 Dmitry Frank 的基本身份验证答案

回答by Tim

More of an alternate solution, but all modern browsers send the domain cookies along with the connection, so using:

更多的替代解决方案,但所有现代浏览器都将域 cookie 与连接一起发送,因此使用:

var authToken = 'R3YKZFKBVi';

document.cookie = 'X-Authorization=' + authToken + '; path=/';

var ws = new WebSocket(
    'wss://localhost:9000/wss/'
);

End up with the request connection headers:

以请求连接头结束:

Cookie: X-Authorization=R3YKZFKBVi

回答by Dmitry Frank

HTTP Authorization header problem can be addressed with the following:

HTTP 授权标头问题可以通过以下方式解决:

var ws = new WebSocket("ws://username:[email protected]/service");

Then, a proper Basic Authorization HTTP header will be set with the provided usernameand password. If you need Basic Authorization, then you're all set.

然后,将使用提供的username和设置正确的基本授权 HTTP 标头password。如果您需要基本授权,那么您已准备就绪。



I want to use Bearerhowever, and I resorted to the following trick: I connect to the server as follows:

Bearer然而,我想使用,我采用了以下技巧:我按如下方式连接到服务器:

var ws = new WebSocket("ws://[email protected]/service");

And when my code at the server side receives Basic Authorization header with non-empty username and empty password, then it interprets the username as a token.

当我在服务器端的代码收到具有非空用户名和空密码的基本授权标头时,它会将用户名解释为令牌。

回答by Gabriele Carioli

You cannot add headers but, if you just need to pass values to the server at the moment of the connection, you can specify a query string part on the url:

您不能添加标头,但是,如果您只需要在连接时将值传递给服务器,您可以在 url 上指定查询字符串部分:

var ws = new WebSocket("ws://example.com/service?key1=value1&key2=value2");

That URL is valid but - of course - you'll need to modify your server code to parse it.

该 URL 是有效的,但是 - 当然 - 您需要修改您的服务器代码来解析它。

回答by Saeed Zarinfam

You can not send custom header when you want to establish WebSockets connection using JavaScript WebSockets API. You can use Subprotocolsheaders by using the second WebSocket class constructor:

当您想使用 JavaScript WebSockets API 建立 WebSockets 连接时,您不能发送自定义标头。您可以Subprotocols通过使用第二个 WebSocket 类构造函数来使用标头:

var ws = new WebSocket("ws://example.com/service", "soap");

and then you can get the Subprotocols headers using Sec-WebSocket-Protocolkey on the server.

然后您可以使用Sec-WebSocket-Protocol服务器上的密钥获取子协议标头。

There is also a limitation, your Subprotocols headers values can not contain a comma (,) !

还有一个限制,您的子协议标头值不能包含逗号 ( ,) !

回答by Norbert Sch?pke

Sending Authorization header is not possible.

发送授权标头是不可能的。

Attaching a token query parameter is an option. However, in some circumstances, it may be undesirable to send your main login token in plain text as a query parameter because it is more opaque than using a header and will end up being logged whoknowswhere. If this raises security concerns for you, an alternative is to use a secondary JWT token just for the web socket stuff.

附加令牌查询参数是一个选项。但是,在某些情况下,将您的主登录令牌以纯文本形式作为查询参数发送可能是不可取的,因为它比使用标头更不透明,并且最终会被记录到任何地方。如果这给您带来了安全问题,另一种方法是将辅助 JWT 令牌仅用于 Web 套接字内容

Create a REST endpoint for generating this JWT, which can of course only be accessed by users authenticated with your primary login token (transmitted via header). The web socket JWT can be configured differently than your login token, e.g. with a shorter timeout, so it's safer to send around as query param of your upgrade request.

创建用于生成此 JWT 的 REST 端点,当然只能由使用您的主要登录令牌(通过标头传输)进行身份验证的用户访问。Web 套接字 JWT 的配置可以与您的登录令牌不同,例如具有更短的超时,因此作为升级请求的查询参数发送更安全。

Create a separate JwtAuthHandler for the same route you register the SockJS eventbusHandler on. Make sure your auth handler is registered first, so you can check the web socket token against your database (the JWT should be somehow linked to your user in the backend).

为您在 上注册 SockJS eventbusHandler 的同一路由创建一个单独的 JwtAuthHandler。确保首先注册您的身份验证处理程序,以便您可以根据您的数据库检查 Web 套接字令牌(JWT 应该以某种方式链接到后端的用户)。

回答by Ryan Weiss

Totally hacked it like this, thanks to kanaka's answer.

由于kanaka的回答,完全像这样破解了它。

Client:

客户:

var ws = new WebSocket(
    'ws://localhost:8080/connect/' + this.state.room.id, 
    store('token') || cookie('token') 
);

Server (using Koa2 in this example, but should be similar wherever):

服务器(在本例中使用 Koa2,但在任何地方都应该类似):

var url = ctx.websocket.upgradeReq.url; // can use to get url/query params
var authToken = ctx.websocket.upgradeReq.headers['sec-websocket-protocol'];
// Can then decode the auth token and do any session/user stuff...

回答by Max Malysh

My case:

我的情况:

  • I want to connect to a production WS server a www.mycompany.com/api/ws...
  • using real credentials (a session cookie)...
  • from a local page (localhost:8000).
  • 我想连接到生产 WS 服务器www.mycompany.com/api/ws...
  • 使用真实凭据(会话 cookie)...
  • 从本地页面 ( localhost:8000)。

Setting document.cookie = "sessionid=foobar;path=/"won't help as domains don't match.

设置document.cookie = "sessionid=foobar;path=/"无济于事,因为域不匹配。

The solution:

解决方案

Add 127.0.0.1 wsdev.company.comto /etc/hosts.

添加127.0.0.1 wsdev.company.com/etc/hosts.

This way your browser will use cookies from mycompany.comwhen connecting to www.mycompany.com/api/wsas you are connecting from a valid subdomain wsdev.company.com.

这样,您的浏览器将mycompany.com在连接时使用 cookie ,www.mycompany.com/api/ws因为您从有效的子域进行连接wsdev.company.com

回答by Poopy McFartnoise

In my situation (Azure Time Series Insights wss://)

在我的情况下(Azure Time Series Insights wss://)

Using the ReconnectingWebsocket wrapper and was able to achieve adding headers with a simple solution:

使用 ReconnectingWebsocket 包装器并能够通过一个简单的解决方案实现添加标头:

socket.onopen = function(e) {
    socket.send(payload);
};

Where payload in this case is:

在这种情况下,有效载荷是:

{
  "headers": {
    "Authorization": "Bearer TOKEN",
    "x-ms-client-request-id": "CLIENT_ID"
}, 
"content": {
  "searchSpan": {
    "from": "UTCDATETIME",
    "to": "UTCDATETIME"
  },
"top": {
  "sort": [
    {
      "input": {"builtInProperty": "$ts"},
      "order": "Asc"
    }], 
"count": 1000
}}}

回答by George

Technically, you will be sending these headers through the connect function before the protocol upgrade phase. This worked for me in a nodejsproject:

从技术上讲,您将在协议升级阶段之前通过连接功能发送这些标头。这在一个nodejs项目中对我有用:

var WebSocketClient = require('websocket').client;
var ws = new WebSocketClient();
ws.connect(url, '', headers);