TL;DR
POST/PUT(PATCH)/DELETE のアクションではその処理でビューを表示せず、リダイレクトしてGETのアクションで表示するのが良い
主張
同じURLでGETとその他(POST/PUT(PATCH)/DELETE)を同じアクションで受けるのはアンチパターンではないか
前提条件
古めのフレームワークだと、コントローラーを作り、アクションとなるメソッドを作れば自動的にルーティングしてくれる。
そのため、そのアクションの中でGETかPOSTを判断して処理を変更する。例えば下記のようなレコードを作成するような処理。
public function create()
{
if ($this->request->is('POST') {
... 作成処理
$this->flash('作成しました!');
}
return view('create');
}
この場合、例えば https://example.com/hoge/create にアクセスすると GET の処理になり、 create のビューが表示され、その中で POST するとその内容で hoge のレコードが作成されるというような設計。
問題点
この場合、スマホなどのブラウザではそのページで放置したまま、ブラウザのプロセスを切り、再度ブラウザを復帰させると同じリクエストを発行してしまう。
それがトリガーとなり、同じレコードを複数作ってしまう。更新や削除でも同様。
実例としては、例えばフリマアプリなどでサンキューページをPOSTリクエストでリダイレクトせずにそのアクションでビューを表示している場合、同じリクエストが発行され重複オーダーをしてしまうなど。
サンキューページが表示されたらそこでタブを削除せず放置し、何かの拍子にそのタブを開くなどはよくあることだろう。
対処法
・RESTfulなアクションを意識し、GET/POSTなどは同じアクションで受けない。 Laravel なら create/store edit/update などを明示的に分けている。
・処理をするアクションではビューを表示せず対応したアクションにリダイレクトする。
上記の例では下記のようにすると良さそう。
public function create()
{
return view('create');
}
public function store()
{
... 作成処理
$this->flash('作成しました!');
return redirect('create'); // GET のアクションにリダイレクトする!
}
こうすることで、復帰してもたかだかレコードを取得(GET)するだけでレコードの追加変更などの影響のない処理になる