[1] [[WebSocket]] の[DFN[[RUBYB[状態符号]@en[status code]]]]は、
[[WebSocket接続]]を閉じる (閉じられた) 理由を示すものです。

;; [2] [[HTTP状態符号]]とは関係ありません。

* 仕様書

[REFS[
- [12] [CITE@en[RFC 6455 - The WebSocket Protocol]] ([TIME[2015-03-11 20:42:50 +09:00]] 版) <http://tools.ietf.org/html/rfc6455#section-7>
- [52] [CITE@en[RFC 6455 - The WebSocket Protocol]] ([TIME[2015-03-11 20:42:50 +09:00]] 版) <http://tools.ietf.org/html/rfc6455#section-11.7>
- [55] [CITE[WebSocket Protocol Registries]] ([TIME[2015-03-06 13:09:47 +09:00]] 版) <https://www.iana.org/assignments/websocket/websocket.xml#close-code-number>
- [57] [CITE[Re: '''['''hybi''']''' Additional WebSocket Close Error Codes]] ([TIME[2012-05-26 08:20:06 +09:00]] 版) <http://www.ietf.org/mail-archive/web/hybi/current/msg09670.html>
- [62] [CITE@en-GB-x-hixie[HTML Standard]] ([TIME[2015-05-06 10:42:35 +09:00]] 版) <https://html.spec.whatwg.org/#feedback-from-the-protocol>
- [77] [CITE@en-GB-x-hixie[HTML Standard]] ([TIME[2015-05-06 10:42:35 +09:00]] 版) <https://html.spec.whatwg.org/#closeevent>
]REFS]

* [CODE[Close]] フレームの状態符号

[3] [[[CODE[Close]]フレーム]]の[[応用データ]]の最初の2[[バイト]]は、
(あれば) [[状態符号]]を表します。

;; [[[CODE[Close]]フレーム]]を参照。

* WebSocket 接続閉じ符号

[30] [DFN[[RUBYB[WebSocket接続閉じ符号]@en[The WebSocket Connection Close Code]]]]は、
[[応用]]が最初に受信した [[[CODE[Close]]フレーム]]に含まれていた[[状態符号]]です。
当該[[フレーム]]が[[状態符号]]を含まない時は、 [DFN[[CODE[[[1005]]]]]] です。
そのような[[フレーム]]が無いまま [[The WebSocket Connection is Closed]]
となった場合は、 [DFN[[CODE[[[1006]]]]]] です。
[CODE(HTTP)[[[1005]]]] と [CODE(HTTP)[[[1006]]]] は、
[[[CODE[Close]]フレーム]]で使っては[['''なりません''']]。 [SRC[>>12]]

[31] [[サーバー]]と[[クライアント]]はそれぞれ[[状態符号]]を送ったり送らなかったりしますが、
両者の認識する[[WebSocket接続閉じ符号]]は同じかもしれませんし、違うかもしれません。

* [CODE(DOMi)@en[CloseEvent]] インターフェイス [CODE(DOMa)@en[code]] 属性

[80] [CODE(DOMi)@en[[[CloseEvent]]]] [[インターフェイス]]の
[DFN[[CODE(DOMa)@en[[[code]]]]]] [[属性]]は、[[WebSocket接続閉じ符号]]を表します。

[81] この[[属性]]は、その[[属性値]]として設定された値を返さなければ[['''なりません''']] [SRC[>>77]]。[[データ型]]は [CODE(IDL)@en[[[unsigned short]]]] で、初期値は
[CODE[[[0]]]] です [SRC[>>77]]。

* 状態符号の一覧

[42] 次の[[状態符号]]が定義されています。
[FIG(list)[
- [DFN[[CODE(HTTP)[[[1000]]]]]] は、目的を達し正常に閉じられることを表します [SRC[>>12]]。
- [DFN[[CODE(HTTP)[[[1001]]]]]] は、[[サーバー]]のダウンや[[Webブラウザー]]が他ページに
[[navigate]] したなど通信の当事者が“いなく”なったことを表します [SRC[>>12]]。
- [DFN[[CODE(HTTP)[[[1002]]]]]] は、プロトコルエラーにより[[接続]]を閉じることを表します
[SRC[>>12]]。
- [DFN[[CODE(HTTP)[[[1003]]]]]] は、受け付けられないデータの種類のため[[接続]]を閉じる
(例えば[[テキスト]]しか理解できないのに[[バイナリー]]を受信した) ことを表します [SRC[>>12]]。
- [DFN[[CODE(HTTP)[[[1007]]]]]] は、データが種類に合っていない
(例えば[[テキスト]]のはずなのに [[UTF-8]] データでない) ため[[接続]]を閉じることを表します
[SRC[>>12]]。
- [DFN[[CODE(HTTP)[[[1008]]]]]] は、方針に反するメッセージを受信したため[[接続]]を閉じることを表します。
他により適切な[[状態符号]]がない時や、隠す必要がある時に使うことができます。 [SRC[>>12]]
- [DFN[[CODE(HTTP)[[[1009]]]]]] は、メッセージが大きすぎるため[[接続]]を閉じることを表します
[SRC[>>12]]。
- [DFN[[CODE(HTTP)[[[1010]]]]]] は、[[handshake]] 時に[[サーバー]]が期待していた[[拡張]]を返さなかったために[[クライアント]]が[[接続]]を閉じることを表します。
必要な[[拡張]]を [[[CODE[Close]]フレーム]]の理由部分に記述する[['''べきです''']]。 [SRC[>>12]]
- [DFN[[CODE(HTTP)[[[1011]]]]]] は、予期せぬ状況で要求を満足できず、[[接続]]を閉じることを表します [SRC[>>12, >>54]]。
- [DFN[[CODE(HTTP)[[[1012]]]]]] は、サービスが再起動されたことを表します。
[[クライアント]]は再接続して構いません。その場合 5s-30s から[[無作為]]に選んだ分遅延して再接続するべきです。 [SRC[>>57]]
- [DFN[[CODE(HTTP)[[[1013]]]]]] は、サービスが過負荷であることを表します。
[[クライアント]]は、(あれば) 異なる [[IPアドレス]]に接続するか、
[[利用者]]の指示があれば同じ [[IPアドレス]]に再接続することとするべきです。 [SRC[>>57]]
- [1014] [DFN[[N[1014]]]] は、より[[上流]]の[[サーバー]]があって、
非妥当な[[応答]]を返したことを表します。 [SRC[>>55]]
]FIG]

[43] [CODE(HTTP)[[[1004]]]] は、予約されています [SRC[>>12]]。

[44] [CODE(HTTP)[[[1015]]]] は、[[TLS handshake]] に失敗して[[接続]]が閉じられたことを示します。
[[[CODE[Close]]フレーム]]で使っては[['''なりません''']]。 [SRC[>>12]]
また[[利用者エージェント]]は使用しません [SRC[>>62]]。

;; [76] [CODE(HTTP)[[[1015]]]] が使われる場面はありません。理論上は[[サーバー]]が接続失敗時に[[ログ]]などで使うのかもしれませんが。。。

[45] [CODE[[[0]]]]-[CODE[[[999]]]] は、使いません [SRC[>>12]]。

[46] [CODE[[[1000]]]]-[CODE[[[2999]]]] は、公開された仕様書で規定されるプロトコルや拡張により、
永続的なものとして利用します [SRC[>>12]]。

[47] [CODE[[[3000]]]]-[CODE[[[3999]]]] は、
[[ライブラリー]]、[[フレームワーク]]、[[応用]]で使うために予約されています。
[[IANA登録簿]]に登録できます。 [SRC[>>12]]

[48] [CODE[[[4000]]]]-[CODE[[[4999]]]] は、
[[私用]]に予約されています。[[IANA登録簿]]に登録できません。
[[応用]]間の事前の合意で使うことができます。 [SRC[>>12]]

;; [56] 実際には「予約」として登録されています [SRC[>>55]]。

[65] 使ってはならない[[状態符号]]や予約されている[[状態符号]]は、
使ってはならないだけで、使われない保証は無いようです。

[4] [CODE(DOMi)@en[[[WebSocket]]]] [[インターフェイス]]の
[CODE(DOMm)@en[[[close]]]] [[メソッド]]では、 [CODE[[[1000]]]]
と [CODE[[[3000]]]]-[CODE[[[4999]]]] しか認められていません。
それ以外は[[例外]]が投げられます。

[53] [[状態符号]]には、[[IANA登録簿]]があります [SRC[>>52, >>55]]。

;; [6] >>5 に [[JSON]] 形式の一覧データファイルがあります。
[REFS[
- [5] [CITE@en[data-web-defs/http-frames.txt at master · manakai/data-web-defs]] ([TIME[2015-05-28 00:33:14 +09:00]] 版) <https://github.com/manakai/data-web-defs/blob/master/doc/http-frames.txt>
]REFS]

* 用途

[10] 現実には、[[WebSocket状態符号]]はあまり積極的に利用されていないようにみえます。

[11] 接続失敗の場合について、[[WebSocket状態符号]]にはあまり有用な情報は現れません。
特に[[クライアント]]については、[[セキュリティー]]のため、
敢えて失敗の詳細な理由が[[スクリプト]]に明かされないことになっています。

[13] 従って実質的には正常終了の場合にしか使いようがありませんが、
通常のデータとして送信せずに接続を閉じつつ情報を送らなければならない場面はほとんどありません。
より詳細な情報 (例えば受信したメッセージが不正だった時に、
そのエラーの詳細情報) を含めたいとすると、一応
[[WebSocket接続閉じ理由]]もあるとはいえ、
通常のデータで送ってから接続を閉じる方が考えることは少なくて済みます。

* 歴史

[7] [[状態符号]]や理由は、 [[Ian Hickson]] 時代の [[WebSocket]]
[[プロトコル]]には存在しませんでしたが、その後 [[IETF]] [[hybi]] により追加されました。

[8] [CITE['''['''hybi''']''' WebSocket Subprotocol Close Code: Bad Gateway]]
([TIME[2016-09-12 20:20:04 +09:00]])
<https://www.ietf.org/mail-archive/web/hybi/current/msg10748.html>

[FIG(quote)[
[FIGCAPTION[
[9] [CITE[WebSocket Protocol Registries]]
([TIME[2016-10-11 10:29:56 +09:00]])
<https://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number>
]FIGCAPTION]

> 1011	Internal Error	'''['''IESG_HYBI''']'''	'''['''RFC6455''']''''''['''RFC Errata 3227''']'''
> 1012	Service Restart	'''['''Alexey_Melnikov''']'''	'''['''http://www.ietf.org/mail-archive/web/hybi/current/msg09670.html''']'''
> 1013	Try Again Later	'''['''Alexey_Melnikov''']'''	'''['''http://www.ietf.org/mail-archive/web/hybi/current/msg09670.html''']'''
> 1014	The server was acting as a gateway or proxy and received an invalid response from the upstream server. This is similar to 502 HTTP Status Code.	'''['''Alexey_Melnikov''']'''	'''['''https://www.ietf.org/mail-archive/web/hybi/current/msg10748.html''']'''
> 1015	TLS handshake	'''['''IESG_HYBI''']'''	'''['''RFC6455''']'''

]FIG]
