Cache-Controlヘッダは仕様通り実装されていない？(2)

[Cache-Controlヘッダは仕様通り実装されていない？](http://qiita.com/shibukawa/items/bdf56e0adbc292666cfb)

自分の投稿へのフォローです。前のも一応残しておきます。

僕は見栄とか張るつもりはないので、分からないことは声を大にして「分からない」と叫んでいきます。「これはこうだよ」という正確な結果を教えてもらえるのが一番助かりますが、そうじゃなくても、不確かでも「これはこうじゃないかな？」という別の解釈とか、「こういうテストをしてみたら？」という提案でもあればまたテストを増やして検証していくのでぜひコメント欄を汚してください。

結果
======

* [テスト結果](https://docs.google.com/spreadsheets/d/18jT3VtCsYuTPZIC1GKDGaoFMEiGYTRcozkFkJRyPR7o/edit?usp=sharing)
* [テストプログラム](https://gist.github.com/shibukawa/2395dda42ab131b65916cd15303ddf77)

前回からの更新
===============

そもそものきかっけは、no-cacheと、must-revalidateの違いが良くわからないということで実験してみたけど益々よくわからない！ということでした。

その後、Jxckさん、tzikさん、@tenpoku1000さんからコメントやら何やらもらったので追試してみました。

まず、subsequent requestは、同一のURLに対する処理、ということで、同じURLを何度も叩くというのみにテストを絞りました。また、リロードというのはブラウザの通常のキャッシュ戦略とは別の動作をするということで、リンクをクリックした結果を見るようにしました。各ステップは次の手順になります。

1. キャッシュクリア
2. index.htmlを表示(next.htmlへのリンクがある)
3. next.htmlに遷移(リンククリック)
4. index.htmlに戻る(ブラウザの戻るボタン)
5. next.htmlに再び遷移(リンククリック)
6. index.htmlに戻る(ブラウザの戻るボタン)
7. 10秒程度待つ
8. next.htmlに再び遷移(リンククリック)

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr"><a href="https://twitter.com/shibu_jp">@shibu_jp</a> must-revalidate と no-cache の違いは以下で読めました。no-cache の意味が明確化されたようです：<br>RFC 7234 — HTTP/1.1: Caching （日本語訳） <a href="https://t.co/JxATrJyov5">https://t.co/JxATrJyov5</a></p>&mdash; 市川 真一 (@tenpoku1000) <a href="https://twitter.com/tenpoku1000/status/748619939683020800">June 30, 2016</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

これを見ると、must-revalidateはサーバから正常の応答がないと504になる、と読めるので、no-cacheとの挙動の違いはサーバからの正常な応答の有無で分かれるのではないか、と推測。golangのhttpサーバを正しく使っていると「正常じゃない応答」というのは生成できないので、とりあえずpanicでハンドラを中断してみることにしました。

実験した結果
==============

Cache-Controlはきちんと実装されているようです。

現在の僕が理解できていること
-----------------------------

1. テストはしてないが、no-storeを指定すると、キャッシュされない(毎回サーバアクセスが発生し、毎回200になる)
2. no-cacheが指定されていると、max-ageは無視される
3. max-ageだけ指定されていると、その時間内であればブラウザはサーバアクセスをサボるので一番効率が良い。
4. サボった時のHTTPレスポンスは、初回と同じ200になった。サボったかどうかはSafariの開発ツールのnetworkタブでは分からない。ただし、レイテンシの時間が2.3ミリ秒→0.13ミリ秒と、20倍近く早くなっている。
5. max-age時間経過後および、no-cacheであれば、サーバアクセスが発生する。サーバが304を返すとキャッシュが利用される。

現在でも分かってないこと
------------------------

1. must-revalidateの役割
2. なぜか前回とmust-revalidateの結果が違う？
3. サーバの応答がない、という状況の再現方法。ハンドラ内でpanicしてみたけど、TCP/IP的にはacceptされているわけで、仕様にある「接続中断」とは違う気がする。

いまRFC 7234 — HTTP/1.1: Caching読み返すと、must-revalidateはsquidとかのプロキシサーバへの司令だったりするのかな、と思ってみたり。キャッシュサーバが本サーバにアクセスできない場合は504を返すんだぞ、という風にも読めなくもない。また今度実験してみる。

**7/9追記**

squidを入れてみて実験してみたものの、やはりmust-revalidateとno-cacheで、動作は変わっているようには見えませんでした。docker便利ですね。以下のコマンドでsquid 3.1.10を起動しました。なお、squidはコンテンツをキャッシュしてしまうので、毎回停止・削除してから起動してます。

```bash
# 3128ポートでsquid起動(もろもろ設定済み)
$ docker run -d -p 3128:3128 --name squid poklet/squid
# squid停止
$ docker stop squid
# squidのコンテナ削除
$ docker rm squid
```

**7/9さらに追記**

squidのコードを確認してくれた方が！

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">Squidのソースを眺めてみたところ一応異なる制御になっているが厳密に504とする部分はTODOと読めた。proxy-revalidateという闇パラメータもある模様。 / “Cache-Controlヘッダは仕様通り実装されて…” <a href="https://t.co/gFvfZBap3i">https://t.co/gFvfZBap3i</a></p>&mdash; Gentoo離脱（しない） (@matsuu) <a href="https://twitter.com/matsuu/status/751603941683507200">July 9, 2016</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>