APIサーバーを、CloudFront使ってHTTPS化したら、カスタムヘッダーが受け取れなかった話
まず、はじめに
タイトルがめちゃくちゃ長くて申し訳ないのですが、ハマった時の私の状況の全てが詰まっています。
その当時、あるWebアプリケーションにRESTAPIを生やして、Reactで作ったクライアントサイトでデータを取得・表示させる、みたいなことをやっていました。
ざっくりしているのですが、React側はS3で静的サイトとして公開していて、APIはEC2上にありました。
この時、API側のapache上でBasic認証がかけられていたので、以下のようにReact側でユーザーのトークン認証を実装する際に「X-HTTP-TOKEN」というカスタムヘッダーを使うことにしました。
- Authorizationヘッダー => Basic認証用
- X-HTTP-TOKEN => トークン認証用
大体機能も実装できたので、そろそろHTTPS化しようかなと思いCloudFrontを差し込んでACMを使うことで無事にHTTPSにすることができました。
ただ、API側がもろもろの事情でまだHTTPSになっていなかったのでこちらも同様の手段でHTTPSにしました。
事件発生
両方をHTTPSにできたのでご満悦だった私は、不意にクライアントから特定のリクエストを送った時にうまく動かないことに気がつきました。
想定
status: 1
result: ...
結果
status: 0
result: null
あれっと思い、調べるとカスタムヘッダーとして使っていた「X-HTTP-TOKEN」が受け取れていないことが判明!
犯人は誰?
ぶっちゃけ犯人は無知な私なんですが、原因がわからずに結構な時間ハマっていました。
というのも、前段に挟んだCloudFrontの設定でなんとかなるんじゃないのかなーとか楽観的に考えてコンソールをポチポチして時間を食いつぶしていたからです。
それでもなかなか解決できずに、PHPの方で受け取っているヘッダーを全て出力すると、、、
そこには、「x-http-token」という変わり果てた元「X-HTTP-TOKEN」の姿がありました。
なぜ、小文字にされていたのかわからなかったのですが、とりあえずAPI側で小文字で受け取るようにすることで、一応の解決となりました。
真相
その後、小文字にされていた理由がわからなくて、ずっとモヤモヤしていたので調べました。
当初はCloudFrontの仕様かなと思っていたので、公式ページをchromeで日本語に翻訳して読み漁っていたのですが、そんな記述は見つかりませんでした(調査不足なだけかも)。
しかし、もしかしてと思い別方向から調べるとあっさりと真相に辿り着きました。
真犯人はHTTP/2でした。
CloudFrontのディストリビューションの設定の際、こういう場面があります。
何にも考えずに上を選んでしまっため気がつかなかったのですが、このHTTP/2にはHTTPヘッダーは小文字しか許さないという仕様があるらしいのです。
これが原因で大文字の「X-HTTP-TOKEN」が受け取れてなかったみたいです。
CloudFront君疑ってごめんなさい。。。
みなさんもHTTP/2を使用する際はお気をつけください
Discussion