はじめに
別ドメインのサーバにブラウザ上からPOSTを送りたい場合に、特定の条件を満たしていないと必ずpreflightとしてOPTIONSを送信を行い、確認がとれた後にPOSTを送信します。
最近使えるようになったAWSのAPI GatewayのHTTP APIでは、CROS設定を行っていてもOPTIONSにはAccess-Control-Allow-Originはつきません。
そのため、ブラウザ側でPOSTを送信するまえにOPTIONSでCROS設定がされていないと拒否されてPOST送信にまでいきません。
既存のAPI GatewayのREST APIで設定するかLambdaなどから強制的にヘッダーをつけたりすれば問題なく送信することはできるようにはなりますが、HTTP APIでなんとかしたい!!となるとうまくいきません。
※ AWSのAPI GatewayのHTTP APIではLambdaからHeaderをつけるような書き方をしても、他のものはつくもののAccess-Control-Allow-OriginなどのCROS関係のヘッダーはつけても削除されてしまいました。悲しい。
解決方法
ざっくりのピックアップですが、以下の条件の場合にはpreflightが飛ばないという仕様になっています。
細かい情報は下部の参考をみてください。
- HTTPリクエストメソッド
- GET, POST, HEAD。
- HTTPリクエストヘッダ
- Content-Type
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
- Content-Type
そのためPOSTの Content-Type が application/json となってる場合には、上記のようにpreflightであるOPTIONSが飛びCROS設定がされていないためブラウザが拒否します。
なので、ajaxで送信時に心で何かが叫んでますが Content-Type を text/plain とすればOPTIONSは飛ばす、すぐにPOST送信が行われるためHTTP APIのCROSの設定通りの挙動で送信が成功します。
同様にJavascriptのfatch apiを使ってjpegなどを送信する場合にはより心で何かが叫んでますがmultipart/form-dataなどとContent-Typeを偽って送信することで、開発環境からもクラウドに向けて送信することができます。
参考
https://fetch.spec.whatwg.org/#cors-preflight-fetch
https://qiita.com/tomoyukilabs/items/81698edd5812ff6acb34