今どきのブラウザはデフォルトで勝手にfavicon.ico呼び出す!知らなくてはまりました。
2020/03/03

思わず2時間もハマってしまった。Go言語でFRAMEWORK無しでURLパスのパラメータ解析をするためにテストプログラムを作ろうとしていた矢先、下記のエラーが出て作業が進まない。どうしてこんな単純なことではまるか!
「runtime error: index out of range goroutine 10 [running]:」
やろうと思ったこと
WEBアプリケーションをGo言語で作る際にURLPathルーティングをするために、URL解析をしようと思って単純に”r.URL.Path”の中身をスライスして最後尾のデータを取り出そうとしたがエラーが止まらない。簡単な文字列スライスなのに何故かエラーが出て訳わからん。
よくみてみるとディスパッチするhandler関数が2回呼ばれているじゃないか!ブラウザは1回叩いているだけなのに何故!?
もしかしてブラウザ側が1回なのに2回リクエストしている????
ブラウザの検証ツールのNetworkタブで確認したところ、ブラウザが勝手にfavicon.icoをGETしてました。
Go言語のスライスは文字列や配列のデータ範囲を指定して部分的に取り出す機能だが、期待している1回目のパスは取れていたもののfavicon.icoパスを取りに行ってるとは想定していなかったので2回目の想定外のGETで添字(要素数)でメモリー参照エラーを引き起こしていた。
プログラムを修正
例えば「http://testserv.jp/jobs/category/3124」のURIの最後尾「3124」の部分を記事IDとして抽出する汎用ルーチンを作ろうと実験するところだった。 “r.URL.Path”のデータを”/”区切り子として最後のデータを取り出すという思惑でした。でもエラーが止まらず、ブラウザーが勝手にfavicon.icoを取りに言っていることがわかったので、それならfavicon.icoをルーティングに登録すりゃいいや!そうすればテストルーチンにフックされないので。ということで修正しました。めでたしめでたし。問題解決。普段ライブラリーやフレームワーク使っているとこうゆうことに気づかないものでいい勉強になりました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package main import ( "fmt" "net/http" "strings" "log" ) //URLパスのチェック、切り出し予定のルーチン作成途中 func handlerCheckPath(w http.ResponseWriter, r *http.Request) { id_num := strings.Split(r.URL.Path,"/") fmt.Println(id_num[len(id_num) - 1])// 要素数-1で最後の添字を求める。 } func handlerFav(w http.ResponseWriter, r *http.Request) { // 何もしません fmt.Println("this call ignore") } func main() { http.HandleFunc("/favicon.ico", handlerFav) // ダミーで宣言してテストルーチンにフックさせない http.HandleFunc("/", handlerCheckPath) err := http.ListenAndServe(":3000", nil) if err != nil { log.Fatal("ListenAndServe: ", err) } } |
なるほど!と思ったこと
今までは、htmlに埋め込まれているfavicon.icoを見つけてブラウザがリクエストしていると思いこんでましたが、あらためて思い込みでした。よく考えてみるとたしかにテストプログラムでfaviconいれてなくてもログには「faviconがない」というエラーがこれまでも出てました。あまりにも当たり前になっていたため気づかなかった。昨今はfaviconの幅が広がりスマホの検索結果にも表示されるようになったので、faviconを自動取得というのもなるほど仕様としてありなんだなーと思いました。