[Laravel] multipart/form-dataを送ったら400になった話
はじめに
フロントエンドでNuxt、バックエンドでLaravelを使って個人開発をしています。
フロントエンドからmultipart/form-data
をPUT
メソッドで送ったところ、Laravel側でリクエストが空と判定され、400 Bad Requestになっていました。
その時に起こったこと、解決策などをまとめていきます。
環境
Nuxtのバージョン ‥‥ 3.17.6
Laravelのバージョン ‥‥ 12
PHPのバージョン ‥‥ 8.4
起きたこと
画像データを扱う関係上、formDataを使ってデータを送いました。
実際の送信部分はこんな感じです。
async update(
data: UpdateRequest | FormData,
options: UseFetchOptions<void> = {},
) {
const defaultOptions: UseFetchOptions<void> = {
method: 'PUT',
body: data,
}
return await useApiAuthFetch(`/api/hogehoge`, {
...defaultOptions,
...options,
})
},
その結果ですが、タイトルにもあるように400が返ってきました。
調べていると、どうやら送信したリクエスト自体が空になっていそうでした。
原因
結論から言うと、PHPの仕様的な問題です。
SAPIレイヤーでは、POST
かつContent-Type: multipart/form-data
の場合にのみ、以下を行います。
- ボディをboundaryごとに分割
- テキスト部分は$_POSTへ入力
- ファイル部分は一時ファイルに保存し、$_FILESへ入力
これをしてくれるため、Laravel側では$request->input()
や$request->file()
を使えます。
PUT でmultipart/form-data
を送ると、PHPはphp://input
に生データをそのまま渡すだけで、自動パースを行いません。
そのため Laravel側の$request->input()
や$request->file()
は空になり、結果的にリクエスト不備として400 Bad Requestが返っていました。
PHPの仕様的な問題ですが、multipart/form-data
はそもそもPOST
メソッドが前提として作られてるので、一概にPHPが悪いわけではないのでご注意を。。。
解決策
multipart/form-data
で送る必要がある場合、更新処理はPUT/PATCH
メソッドを使わず、POST
メソッドで送り、_method=PUT
を追加します。
formData.append(`_method`, `PUT`)
Laravel はこの_method
を見て内部的にPUT
メソッドとして処理するため、ルート定義はそのままRoute::put(...)
を使えます。
備考
Discussion