skip to content

In a WebSocket opening handshake, what does the client's `Sec-WebSocket-Protocol` field offer, and how must the server answer?

level: juniorimportance: must knowfreq 62%

answer

  1. one field, one decision
  2. ordered list, server's choice
  3. zero or one comes back
  4. echoed verbatim on the 101
  5. an unoffered name fails the connection

basics

~20 s

Sec-WebSocket-Protocol carries an ordered list of application protocol names the client can speak. The server selects at most one and echoes exactly that name in its 101 response; returning two names, or one never offered, fails the connection.

solid answer

~40 s

The client puts `Sec-WebSocket-Protocol` on the opening HTTP/1.1 request beside `Upgrade: websocket` and `Sec-WebSocket-Version: 13`. Its value is a comma-separated list of subprotocol names, ordered by the client's preference, naming the application protocols it is able to speak once the socket is open. The server then selects **zero or one** of those names and repeats the chosen one, verbatim, in the `101 Switching Protocols` response. Three outcomes follow: one offered name comes back and both ends speak it; the field is absent, which is legal and means no subprotocol was agreed; or the response carries a name the client never offered, or more than one name, in which case the client must fail the WebSocket connection. The name itself is an opaque token — the WebSocket layer never checks that the messages match it.

code

http · 13 lines
http
GET /cues HTTP/1.1
Host: desk.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Protocol: cue.v2.example.com, cue.v1.example.com

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: cue.v1.example.com

go deeper

for a junior

Know that the field exists on the opening request, that its value is a list of names, and that the server echoes at most one of them on the 101 response. Being able to point at those two lines of a handshake is the screening bar.

for a middle

Explain the rule precisely: zero or one name, drawn from the offer, repeated verbatim. Then explain what the client must do when the response breaks that rule, and why a name coming back is not a promise about message content.

for a senior

Show the operational habit: log the negotiated name per connection, put the protocol version in the name so skew is visible at connect time, and decide deliberately what a client does when the server agrees to no subprotocol.

for a principal

The judgment is whether one named protocol spans every client your product ships, or whether you accept several names on one endpoint and pay for the branching. Naming is also a contract with teams you do not control.

## What the client offers A WebSocket connection begins as an ordinary HTTP/1.1 request that asks to change protocols. Alongside `Upgrade: websocket`, `Connection: Upgrade`, `Sec-WebSocket-Version: 13` and `Sec-WebSocket-Key`, the client may send `Sec-WebSocket-Protocol`. Its value is a comma-separated list of **subprotocol names** — the application-level protocols this client can speak once the socket carries bytes. Two properties of that list do the work: - It is **ordered**, and the order states the client's preference. It does not bind the server, which may select any name from the list. - Each entry is a **token**, not a description. Published subprotocols register their names; a private protocol conventionally uses a domain-scoped name so it cannot collide with anybody else's. The field is optional. A client that sends none is saying it proposes no named protocol, and if the socket opens, whatever the two sides speak was agreed somewhere outside the handshake — in a document, or by both ends shipping from the same repository. ## What the server is allowed to answer RFC 6455 gives the server a narrow choice: it selects **zero or one** of the offered values and echoes the selected one in the `101 Switching Protocols` response. | The 101 response carries | What it means | What the client does | |---|---|---| | exactly one name from the offer | that subprotocol is agreed | speak that protocol | | no `Sec-WebSocket-Protocol` field | no subprotocol was agreed | the application decides: continue, or close | | a name that was never offered | the server broke the rule | fail the WebSocket connection | | more than one name | the server broke the rule | fail the WebSocket connection | The last two rows matter more than they look. Validating the response is part of completing the handshake, so a client that rejects it never reaches an established connection — which means there is no socket on which to send a Close control frame. The client abandons the connection and reports the failure. That is a different shape of ending from a close code, and it is the ending the specification prescribes here. Row two is the one candidates most often get wrong. An absent field is **not** an error: the server is entitled to accept the upgrade and agree to no named protocol at all. Whether that is usable is an application question, not a protocol one. ## The name is opaque, and that is the real trap The WebSocket protocol does not know what any subprotocol name means. It carries the token through the handshake, hands the agreed string to both applications, and stops. Nothing on the wire checks that the messages that follow match the protocol named, because the frames carry text or binary payloads and no schema at all. So the genuine production failure is not a rejected handshake. It is two ends that **both believe the negotiation succeeded** and disagree about what the messages mean — most often because the message grammar behind one name changed while the name stayed the same, and half the fleet is running the old reading of it. The defence is to make a semantic change a **new token**. Put the version in the name, offer the new and old names together, and let the handshake record which reading is in force: 1. The client offers `cue.v2.example.com, cue.v1.example.com`. 2. A server that still understands both selects the first one it prefers. 3. A server that has dropped the old reading selects the new name — or, if it cannot speak either, returns no subprotocol rather than pretending. 4. Every connection's negotiated name is then a fact you can log, which turns a schema mismatch into something visible at connect time instead of a decoding error an hour later. ## When the response carries no subprotocol A client that genuinely requires a named protocol must check the response and decide for itself. Some applications carry a sensible default and continue. A client that cannot continue closes the connection it has just opened — and here it **does** have an established socket, so it sends a Close control frame. The specification defines no code meaning "you agreed to no subprotocol", so applications use a policy-violation code or one from the ranges reserved for application use, and put the explanation in the close reason. ## What to check on every connection - The negotiated name is on the offered list. - Exactly one name came back, not several. - The application actually implements the name that was selected, rather than assuming its own first preference won.

  • The client listed its preferred name first and the server selected the second. Has the server misbehaved?
    No. The order expresses the client's preference, not an obligation. The server may select any name from the offer, and a client that cannot cope with its second choice should not have offered it. The only server errors are selecting a name that was not offered and selecting more than one.
  • How do you version an application protocol carried over a WebSocket without breaking clients already connected?
    Put the version in the subprotocol name and offer both, newest first. Old clients negotiate the old name, new clients the new one, and the server answers each with the reading it will actually use. A connection already open keeps whatever it negotiated until it closes — the name is fixed for the life of that socket.
  • What does a client learn if the 101 response omits `Sec-WebSocket-Protocol` entirely?
    That the socket is open and no subprotocol was agreed. That is legal, not a handshake error. The application decides whether it can proceed on an unnamed convention; if it cannot, it closes the now-established connection with a close frame and an explanatory reason.

Two theatre crews on one intercom line agreeing, before the house opens, which cue-sheet notation they will both use. The line carries any sounds at all; the notation is what makes them mean a cue.

saying these in an interview costs you the question

  • Says the server returns every name it supports for the client to choose from
  • Thinks the client's first listed name is binding on the server
  • Believes a missing subprotocol field in the 101 means the upgrade was refused
  • Assumes the negotiated name makes the WebSocket layer validate message shape
  • Thinks a subprotocol can be renegotiated later on the open socket