0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

WEBアプリケーションで同じアクションで複数のメソッドを受け付けるのはアンチパターンではないかという主張

Posted at

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)するだけでレコードの追加変更などの影響のない処理になる

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?