WEBサイトやWEBアプリケーションを開発していると、
ページ滞在時間を計測したい場合など、
ページを離れる直前にどこかにリクエストを投げたいケースがあるかもしれません。
僕は、ユーザーがどのページにどれくらいいるのか計測したいシーンがありました。
ただ、ページを離れる直前にどこかにリクエストを投げる方法は案外出回っておらず、
かつ普通にページ遷移直前にサーバーにリクエストすると
ページ遷移したあとリクエスト処理が中断されるみたいなことがあり、
僕は割と困ったのでシェアします。
注意点は、POSTリクエストしか送れないこと。(GETやPUTを送る方法があればぜひ教えてください。)
そして今回はjQueryを想定して書いてます。
ReactやVueなんかだともっと簡単に書けるのかな?
結論からいうと以下のコードでできます。
$(window).on('beforeunload', e => {
const blob = new Blob([{}], { type: 'application/x-www-form-urlencoded' });
navigator.sendBeacon('送りたいURL', blob);
e.preventDefault();
})
使用環境
Chrome
Laravel
ES6
解説
beforeunload
beforeunloadでページ遷移直前の処理をかけます。
通常はなにか編集中の画面で保存せずに画面遷移をしようとした時に、
「このままページを離れますか?」
といったメッセージを出す用途で使われるっぽい。
sendBeacon
sendBeaconを使います。
ベーコンじゃないです。
センドビーコンです。
「ビーコン」とは何かを誘導したり、信号を送ったりするものを指す言葉です。
灯台や狼煙(のろし)という意味があるので、
複雑なことは考えずとりあえず投げつけますよ的なニュアンスで僕は捉えています。
axiosだったり他の方法でリクエストすると、リクエスト直後にページ遷移した場合に、そのリクエスト処理が中断されるっぽい。
だから、リクエストをサーバーに投げつけてかつちゃんと処理をやってもらうには、sendBeaconを使わないといけないっぽい。
ただし、sendBeaconはPOSTしか投げられないので要注意。GETとかでこれやりたいシーンもあるよなぁ。わかる方いれば教えてください。
かつ、Content-typeがapplication/json
だとcorsに引っかかる(ブラウザの仕様?)ので、
application/x-www-form-urlencoded
で送っています。
Blobの第一引数にリクエストボディをセットしてあげることも可能です。
e.preventDefault()
これをいれることによってデフォルトの挙動をキャンセルしてます。
デフォルトの挙動だと
「このままページを離れますか?」
っていうメッセージが出ちゃうみたいなので。(この辺曖昧)
引数のeを受け取らず、かつこのe.preventDefault()を受け取らないって方法も全然ありな気がする。
めんどくさいので試してないし、あんまりこの辺わからないので、気になる方はやってみてください。
以上!