net/httpパッケージでhandlerが二回実行されることの原因を探す

本記事は下記を参考にしています。

qiita.com


以下から始まる本記事はいつも以上に信憑性がありません。


結論

  • faviconを取得する処理が走っている
  • faviconを取得してどう処理するかはブラウザごとに異なる

開発環境

# Go
/go/src # go version
go version go1.17.8 linux/amd64

# Chrome
バージョン: 99.0.4844.51(Official Build) (x86_64)

# Firefox
98.0 (64 ビット)

# Safari
バージョン14.1.2 (16611.3.10.1.6)

net/httpパッケージでhandlerが二回実行される

package main

import (
    "html/template"
    "log"
    "net/http"
    "time"
)

func main() {
    http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
        log.Println(time.Now())  // *1
        t, err := template.ParseFiles("index.html")
        if err != nil {
            log.Fatal(err)
        }

        if err := t.Execute(rw, nil); err != nil {
            log.Fatal(err)
        }
    })

    http.ListenAndServe(":8080", nil)
}

Chromelocalhost:8080 にアクセスすると、*1 以降が2回呼ばれた。

調べると、こちらの記事 がヒットした。
どうやら http://localhost:8080/favicon.ico にアクセスしているとのことなので、ChromeのDeveloper Toolで通信を確認した。

f:id:tokizuoh:20220313122827p:plain
ChromeのDeveloper Toolで localhost:8080 アクセス時の通信を確認

どちらもStatus Codeが200で返ってきた。
Chrome側が http://localhost:8080/favicon.ico にアクセスしていることが分かった。

faviconの設定をしていないのに200で返ってくるのはおかしくないか?

f:id:tokizuoh:20220313123220p:plain

favicon表示領域に鎮座するJenkinsおじさん

過去に localhost:8080 にJenkinsをリバースプロキシしたことがあり、且つ、Chrome経由でアクセスしていたため、キャッシュを見ていることは予想がつく。

過去にJenkinsにアクセスしたことがないFirefoxlocalhost:8080 にアクセスしてみる。

Firefoxlocalhost:8080 にアクセス

f:id:tokizuoh:20220313125818p:plain
Firefoxのウェブ開発ツールで localhost:8080 アクセス時の通信を確認

Chromeより見やすい。
Firefoxからのアクセス時はGoのソースコード内のhandlerは1回しか呼ばれなかった。
http://localhost:8080/favicon.ico は404を返している。

faviconのキャッシュがブラウザに残ってない且つ、設定も行われてない場合はhandlerは一回しか実行されない?

とりあえず、faviconを取得する処理はChromeだけではなくFirefoxにもあることが分かった。

ダメ押しでSafariでも見てみる。

Safarilocalhost:8080 にアクセス

f:id:tokizuoh:20220313135455p:plain
SafariのWebインスペクタで localhost:8080 アクセス時の通信を確認

Safariはどちらも200を返した。
ここのあたりはブラウザ依存っぽい(= ガチガチな規格で定められていない)ことが分かったのでOK。

参考