HTTP headers in Websockets client API

后端 未结 11 2217
情话喂你
情话喂你 2020-11-22 10:41

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.

相关标签:
11条回答
  • 2020-11-22 10:48

    Updated 2x

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

    Longer answer:

    There is no method in the JavaScript WebSockets API for 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.

    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:

    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

    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 - No longer functional):

    NOTE: the following information is no longer accurate in any modern browsers.

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

    var ws = new WebSocket("ws://username:password@example.com")
    

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

    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).

    Thanks to Dmitry Frank's for the basic auth answer

    0 讨论(0)
  • 2020-11-22 10:48

    You can pass the headers as a key-value in the third parameter (options) inside an object. Example with Authorization token. Left the protocol (second parameter) as null

    
    ws = new WebSocket(‘ws://localhost’, null, { headers: { Authorization: token }})
    
    

    Edit: Seems that this approach only works with nodejs library not with standard browser implementation. Leaving it because it might be useful to some people.

    0 讨论(0)
  • 2020-11-22 10:50

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

    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):

    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...
    
    0 讨论(0)
  • 2020-11-22 10:53

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

    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
    
    0 讨论(0)
  • 2020-11-22 10:59

    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).

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

    The solution:

    Add 127.0.0.1 wsdev.company.com to /etc/hosts.

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

    0 讨论(0)
  • 2020-11-22 11:04

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

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

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

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

    0 讨论(0)
提交回复
热议问题