[504] [[HTTP]] の [DFN[[CODE(HTTP)@en[[[Retry-After:]]]]]] [[ヘッダー]]は、
次に[[要求]]を送信するまでに待つべき時間を指定するものです。

[529] [[Webブラウザー]]では実装されていませんが、特別な用途の[[利用者エージェント]]や
[[Googlebot]] は [CODE(HTTP)[[[503]]]] [[応答]]後の再試行の時期の決定のために参照しているようです。

* 仕様書

[REFS[
- [509] '''[CITE@en[RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content]] ([TIME[2014-08-07 05:54:02 +09:00]] 版) <https://tools.ietf.org/html/rfc7231#section-7.1.3>'''
- [507] [CITE@en[RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content]] ([TIME[2014-08-07 05:54:02 +09:00]] 版) <https://tools.ietf.org/html/rfc7231#section-6.5.11>
- [505] [CITE@en[RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content]] ([TIME[2014-08-07 05:54:02 +09:00]] 版) <https://tools.ietf.org/html/rfc7231#section-6.6.4>
- [6] [CITE[OData Version 4.0 Part 1: Protocol Plus Errata 01]] ([TIME[2014-09-04 16:00:00 +09:00]] 版) <http://docs.oasis-open.org/odata/odata/v4.0/odata-v4.0-part1-protocol.html#_Toc393958698>
- [11] [CITE@en[RFC 6585 - Additional HTTP Status Codes]] ([TIME[2015-11-02 08:48:01 +09:00]] 版) <http://tools.ietf.org/html/rfc6585#section-4>
]REFS]

* 意味

[510] [CODE(HTTP)@en[[[Retry-After:]]]] [[ヘッダー]]は、
[[利用者エージェント]]が続きの[[要求]]を行う前に待つ[RUBYB[べき]@en[ought to]]長さを示します。
[SRC[>>509]]

[512] [CODE(HTTP)[[[3xx]]]] [[応答]]では、[[リダイレクト]]先の[[要求]]を発行する前に[[利用者エージェント]]が待つ[RUBYB[べき]@en[ought to]]最低時間を示します。
[SRC[>>509]]

[5] [CODE(HTTP)[[[503]]]] [[応答]]では、[[サービス]]が利用不能であると思われる時間を示します。
[SRC[>>509]]

;; [516] それ以外の[[状態符号]]では意味は定義されていませんが、
なぜか特に禁止もされていません。

[7] [[OData]] では [CODE(HTTP)[[[202]]]] でも [CODE(HTTP)@en[[[Location:]]]] と
[CODE(HTTP)@en[[[Retry-After:]]]] を使うことを認めており、 [CODE(HTTP)@en[[[Retry-After:]]]]
は [CODE(HTTP)@en[[[Location:]]]] の [[URL]] にアクセスする前に待つべき[[時間]]を表します
[SRC[>>6]]。

* 構文

[506] [CODE(HTTP)@en[[[Retry-After:]]]] [[ヘッダー]]の値は、
その時刻以降に再試行を開始するべき[[絶対時刻]]を[[HTTPの日付形式]]として指定するか、
または待つべき相対的な[[時間]]を[[デルタ秒]]として[[整数]]で指定するかのいずれかです [SRC[>>509]]。

[FIG(railroad)[
= |
== [CODE(ABNF)@en[[[HTTP-date]]]]
== [CODE(ABNF)@en[[[delay-seconds]]]]
]FIG]

* 文脈

[415] [[鯖]]は、 [CODE(HTTP)[[[413]]]] [[応答]]において、
その状態が一時的なものである場合、[[クライアント]]が再試行してもよい時刻を表す
[CODE(HTTP)@en[[[Retry-After:]]]] [[ヘッダー]]を[[生成]]する[['''べきです''']] [SRC[>>507]]。

[508] [[鯖]]は、 [CODE(HTTP)[[[503]]]] [[応答]]において、
[[要求]]を再試行するまで[[クライアント]]が待つべき時間を提案する
[CODE(HTTP)@en[[[Retry-After:]]]] [[ヘッダー]]を送っても[['''構いません''']] [SRC[>>505]]。

[12] [CODE[[[429]]]] [[応答]]で [CODE(HTTP)@en[[[Retry-After:]]]]
[[ヘッダー]]を使うことができます [SRC[>>11]]。

* 3xx での用法

;; >>512

[1] 実際 redirect で2分とか待たされたら嫌かも。
その間 [[UA]] は、利用者は、何をしてればいいんやねん?
みたいな。

応答で送られてきた[[実体]]を利用者に見せつつ、
何秒後に移動します。。。というメッセージを出すといいのかな。
非対話 UA だったら・・・どうするのだろう?

[2] よく、移転しますた。っていうメッセージを [CODE(HTTP)[[[200]]]] で出して、
[CODE(HTTP)[[[Refresh]]]] で数秒後に飛ばすというのをやってますけど、
それの標準化された代替として使えるかな??

[515] 実装がこれに対応しているという話は聞いたことがありませんし、
[[鯖]]で使われているという話も聞いたことがありません。

* 歴史

[FIG(quote)[
[FIGCAPTION[
[505] RFC 1945 (HTTP/1.0) D.2.8; RFC 2068 (HTTP/1.1) 14.38; RFC 2616 (HTTP/1.1) 14.37 Retry-After
]FIGCAPTION]

> The Retry-After response-header field can be used with a 503 ([DEL[[INS[{1945}]] service unavailable]] [INS[Service Unavailable]])
response to indicate how long the service is expected to
be unavailable to the requesting client. [INS[[INS[{2616}]] This field MAY also be used with any 3xx (Redirection) response to indicate the minimum time the user-agent is asked wait before issuing the redirected request.]] The value of this field can
be either an HTTP-date or an integer number of seconds (in decimal)
after the time of the response.

[CODE(HTTP)[Retry-After]] [[応答頭欄]]は、
どれだけの間サービスが利用不能と思われるかを要求してきたクライアントに示すために
[CODE(HTTP)[[[503]]]] (サービス利用不能) 応答と共に使うことができます。 [INS[この欄は、[[再指向]]要求を発行する前に利用者エージェントに待機して欲しい最低時間を示すために [CODE(HTTP)[[[3xx]]]] (再指向) 応答でも使って'''構いません'''。]]
この欄の値は、 [CODE(HTTP)[[[HTTP-date]]]] か、応答の時刻の後の秒数 (十進整数)
のいずれかです。

[INS[

> [INS[{2968,2616}]]
- Retry-After  = "Retry-After" ":" ( HTTP-date | delta-seconds )

> Two examples of its use are
- Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
- Retry-After: 120

> In the latter example, the delay is 2 minutes.

後者の例では、間隔は2分です。
]INS]
]FIG]

* 実装

[517] [CODE(HTTP)@en[[[Retry-After:]]]] [[ヘッダー]]は
[[Webブラウザー]]本体では実装されていません。

[523] [[Firefox]] の [[Bugzilla]] には2004年から登録されています [SRC[>>522]] が、
10年経っても実装の見込みはありません。

[REFS[
- [522] [CITE@en[230260 – Retry-After sent with HTTP 503 response is ignored]] ([TIME[2014-09-01 10:21:35 +09:00]] 版) <https://bugzilla.mozilla.org/show_bug.cgi?id=230260>
]REFS]

[520] [[Chrome]] の [[captive portal]] 検出機能では、 [CODE(HTTP)[[[503]]]]
からの再試行時に [CODE(HTTP)@en[[[Retry-After:]]]] の値を尊重するようです [SRC[>>518, >>519]]。 

[REFS[
- [518] [CITE@en['''['''chrome''']''' Revision 169246]] ([TIME[2014-09-01 10:18:56 +09:00]] 版) <http://src.chromium.org/viewvc/chrome?revision=169246&view=revision>
- [519] [CITE[Issue 11419070: Added detection timeouts and usage of Retry-After HTTP header. - Code Review]] ([TIME[2014-09-01 10:19:01 +09:00]] 版) <https://chromiumcodereview.appspot.com/11419070>
]REFS]

[524] [[Mozilla Project]] の [[Android]] 関連機能では [CODE(HTTP)[[[503]]]] からの再試行時に
[CODE(HTTP)@en[[[Retry-After:]]]] の値を尊重するようです [SRC[>>521]]。

[REFS[
- [521] [CITE@en-US[mozilla-central: Search]] ([TIME[2014-09-01 10:19:57 +09:00]] 版) <https://hg.mozilla.org/mozilla-central/log?rev=Retry-After>
]REFS]

[526] [[Android]] で用いられる [[GCM]] では [CODE(HTTP)[[[503]]]] で
[CODE(HTTP)@en[[[Retry-After:]]]] を尊重することが求められています [SRC[>>525]]。

[REFS[
- [525] [CITE[GCM HTTP Connection Server | Android Developers]] ([TIME[2014-09-01 10:23:05 +09:00]] 版) <https://developer.android.com/google/gcm/http.html>
]REFS]

[528] [[Googlebot]] は [CODE(HTTP)[[[503]]]] 時の [CODE(HTTP)@en[[[Retry-After:]]]]
の値をスケジューリングの参考にしているようです [SRC[>>527]]。

[REFS[
- [527] [CITE@en[Official Google Webmaster Central Blog: How to deal with planned site downtime]] ([TIME[2014-08-27 09:16:37 +09:00]] 版) <http://googlewebmastercentral.blogspot.jp/2011/01/how-to-deal-with-planned-site-downtime.html>
]REFS]

* 例

[FIG[
[FIGCAPTION[
[513] [[絶対時刻]]を指定した例 [SRC[>>509]]
]FIGCAPTION]

[PRE(HTTP code)[
Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
]PRE]
]FIG]

[FIG[
[FIGCAPTION[
[514] [[相対時刻]]を指定した例 [SRC[>>509]]
]FIGCAPTION]

[PRE(HTTP code)[
Retry-After: 120
]PRE]
]FIG]

* メモ

[3] [CODE(HTTP)[[[423]]]] (固定済) あたりにも [CODE(HTTP)[Retry-After]] が使えてもいい気がするのだけどどうよ?

[4]
>>3 Lock は他の処理との相互作用だから、予測がつかない、ってことかもしれませんけど、経験的に予想できることもありますから、使ってもいいかもしれませんね。

[FIG(quote)[
[FIGCAPTION[
[8] [CITE[Help Desk API for Developers | Freshdesk]]
([[humans.txt]] 著, [TIME[2015-08-29 17:23:28 +09:00]] 版)
<http://freshdesk.com/api#ratelimit>
]FIGCAPTION]

> 
> The number of API calls per hour is restricted to 1000. If your API request is received after the limit has been reached, Freshdesk will give you an error response. The "retry-after" value in the response header will tell you how long you need to wait before you send another API request.
> Response
> HTTP STATUS: HTTP 403 Forbidden
> Headers:
> "Retry-After": <seconds>

]FIG]


[FIG(quote)[
[FIGCAPTION[
[9] [CITE[Rate Limiting | Content API]]
([TIME[2015-08-29 17:28:47 +09:00]] 版)
<https://box-content.readme.io/reference#rate-limiting>
]FIGCAPTION]

> HTTP/1.1 429 Too Many Requests
> Retry-After: {retry time in seconds}

]FIG]


[FIG(quote)[
[FIGCAPTION[
[10] [CITE[Rate Limiting - Riot Games API]]
([TIME[2015-12-08 17:51:34 +09:00]] 版)
<https://developer.riotgames.com/docs/rate-limiting>
]FIGCAPTION]

> If a call exceeds the user or service rate limit for a given period of time, then subsequent calls made to limited endpoints will return a 429 "Rate limit exceeded" HTTP response until the rate limit expires.
> In addition to the response code, some additional headers will be included in the response that provide more information.
> Retry-After - The remaining number of seconds before the rate limit resets.
> X-Rate-Limit-Type - The rate limit type, either "user" or "service".
> If the above headers are not included in the response, then the rate limit was not enforced by the API infrastructure, but rather by the underlying service to which the request was proxied.

]FIG]

[FIG(quote)[
[FIGCAPTION[
[13] [CITE@en[RFC 7030 - Enrollment over Secure Transport]]
([TIME[2016-06-19 16:27:56 +09:00]])
<https://tools.ietf.org/html/rfc7030#section-4.2.3>
]FIGCAPTION]

> 
>    If the server responds with an HTTP '''['''RFC2616''']''' 202, this indicates
>    that the request has been accepted for processing but that a response
>    is not yet available.  The server MUST include a Retry-After header
>    as defined for HTTP 503 responses.  The server also MAY include
>    informative human-readable content.  The client MUST wait at least
>    the specified "retry-after" time before repeating the same request.
>    The client repeats the initial enrollment request after the
>    appropriate "retry-after" interval has expired.

]FIG]


[FIG(quote)[
[FIGCAPTION[
[14] [CITE@en[Backoff indicators — Kinto 8.1.5 documentation]]
([TIME[2018-02-21 01:03:16 +09:00]])
<https://kinto.readthedocs.io/en/latest/api/1.x/backoff.html>
]FIGCAPTION]

> A Retry-After header will be added if response is an error (>=500). See more details about error responses.

]FIG]


[FIG(quote)[
[FIGCAPTION[
[15] [CITE@ja[Firebase Cloud Messaging の HTTP プロトコル]]
([TIME[2020-02-19 13:19:29 +09:00]])
<https://firebase.google.com/docs/cloud-messaging/http-server-ref?hl=ja>
]FIGCAPTION]

> 500~599 の範囲に含まれるエラー(500 や 503 など)は、リクエストの処理中に FCM 接続サーバーで内部エラーが発生したか、サーバーが(タイムアウトなどの理由で)一時的に利用できないことを示します。送信者はレスポンスに含まれている Retry-After ヘッダーを適用し、後で再試行する必要があります。アプリサーバーでは指数バックオフを実装する必要があります。

]FIG]
