[Laravel] AjaxでPOSTしようとすると "The payload is invalid"で怒られる


LaravelでSPAを作っていて、POSTを行うためにCookieから XSRF-TOKEN を取り出してヘッダに X-XSRF-TOKEN として付与してリクエストしていたら 500 エラー The payload is invalidで弾かれたのでその対処法です。

TL;DR

ヘッダにつけるトークンを decodeURIComponent()して差し上げる

くわしく

Laravelを使ったアプリケーションにPOSTリクエストする際は、基本的にCSRF対策がされているので、予めLaravelが発行したCSRFトークンを付与しないと 419 エラーで怒られます。通常のフォームからリクエストする際は特に意識する必要はありませんが、SPAなどで非同期にPOSTを行う場合は、Laravel様がリクエストのたびにCookieに書き込んでくださる XSRF-TOKEN という値をヘッダに含める必要があります。しかしながら、 XSRF-TOKEN を付与したにも関わらず、Laravel様に怒られてしまったのでその対処法です。

Cookie に XSRF-TOKEN として格納される値はURLエンコードされているので、 XSRF-TOKEN に含まれる = などのURLに使用できない文字はパーセントエンコーディングされて格納されます(=%3D)。そのため、その値をそのままヘッダに X-XSRF-TOKEN としてつけても無効なトークンと見なされ、Laravel様に弾かれます。

したがってdecodeURIComponent()を使ってパーセントエンコーディングされた文字を元に戻してリクエストに含めることで、Laravel様が正しいトークンとして認識してくださるようになります。

%3D が含まれてたり含まれてなかったりするせいで、たまにリクエストが通るのでよくわからなかった。

以下のような関数でCookieの値を取得するとする。

getCookieValue
function getCookieValue(targetKey) {
  for (let cookie of document.cookie.split(";")) {
    const [key, value] = cookie.trim().split("=");
    if (key === targetKey) {
      return value;
    }
  }

  return "";
}

この関数で単純に getCookieValue("XSRF-TOKEN") とすると

X-XSRF-TOKEN
XeyJpdiIDInIyQWdNb2tzADRUXC9CVjFzQWVTVUpBPT0iLCJ2YWx1ZSI6InFiUlc3ZVo2RXVNVXl0OUFTZnc1UGRpK05kUlUzWUJhOENBDDRsVjRFWnFpZVFOaUSzaThyNDxYdzY5Z0lacG0iLCJtYWMiOiJjY2YzNDNhYTdhZGUyZTFkZDFhMGM2MzUxYjE1NTdjM2FiNzU2ZTU3NjA1YzYzYDc5NDJmOGE2NzVmNWYwOWQ4In0%3D

みたいな値(末尾に %3D がある)が取れるので、decodeURIComponent を使って

decodeURIComponent(X-XSRF-TOKEN)
XeyJpdiIDInIyQWdNb2tzADRUXC9CVjFzQWVTVUpBPT0iLCJ2YWx1ZSI6InFiUlc3ZVo2RXVNVXl0OUFTZnc1UGRpK05kUlUzWUJhOENBDDRsVjRFWnFpZVFOaUSzaThyNDxYdzY5Z0lacG0iLCJtYWMiOiJjY2YzNDNhYTdhZGUyZTFkZDFhMGM2MzUxYjE1NTdjM2FiNzU2ZTU3NjA1YzYzYDc5NDJmOGE2NzVmNWYwOWQ4In0=

になおしてヘッダに含める。

axios_config
axios.interceptors.request.use(config => {
  config.headers["X-XSRF-TOKEN"] = decodeURIComponent(getCookieValue("XSRF-TOKEN"));
  return config;
});