POSTリンクの正しい使い方
Webアプリケーション、特に管理インターフェースでは、サーバーの状態を変更するアクションはHTTPメソッドGETを介して実行されるべきではないという基本的なルールがあるべきです。メソッド名が示すように、GETはデータの取得にのみ使用されるべきであり、変更には使用されるべきではありません。 レコードの削除などのアクションには、POSTメソッドを使用する方が適しています。理想的にはDELETEメソッドですが、JavaScriptなしでは呼び出せないため、歴史的にPOSTが使用されています。
実践的にはどうすればよいでしょうか?この簡単なトリックを利用してください。テンプレートの最初に、postForm
という識別子を持つ補助フォームを作成し、それを削除ボタンに使用します。
<form method="post" id="postForm"></form>
このフォームのおかげで、古典的なリンク <a>
の代わりに、通常のリンクのように見えるように視覚的に調整できるボタン <button>
を使用できます。たとえば、CSSフレームワークBootstrapは、ボタンが他のリンクと視覚的に区別されないようにするクラス
btn btn-link
を提供します。属性 form="postForm"
を使用して、事前に準備されたフォームにリンクします。
<table>
<tr n:foreach="$posts as $post">
<td>{$post->title}</td>
<td>
<button class="btn btn-link" form="postForm" formaction="{link delete $post->id}">削除</button>
<!-- <a n:href="delete $post->id">delete</a> の代わりに -->
</td>
</tr>
</table>
リンクをクリックすると、delete
アクションが呼び出されます。リクエストがPOSTメソッドと同一ドメインからのみ受け入れられるようにするため(これはCSRF攻撃に対する効果的な防御策です)、#[Requires]
属性を使用します。
use Nette\Application\Attributes\Requires;
class AdminPresenter extends Nette\Application\UI\Presenter
{
#[Requires(methods: 'POST', sameOrigin: true)]
public function actionDelete(int $id): void
{
$this->facade->deletePost($id); // レコードを削除する仮のコード
$this->redirect('default');
}
}
この属性はNette Application 3.2以降存在し、その可能性については \#Requires属性の使い方 ページで詳しく知ることができます。
actionDelete()
アクションの代わりに handleDelete()
シグナルを使用する場合、シグナルにはこの保護が暗黙的に設定されているため、sameOrigin: true
を指定する必要はありません。
#[Requires(methods: 'POST')]
public function handleDelete(int $id): void
{
$this->facade->deletePost($id);
$this->redirect('this');
}
このアプローチは、アプリケーションのセキュリティを向上させるだけでなく、正しいWeb標準と実践の遵守にも貢献します。状態を変更するアクションにPOSTメソッドを利用することで、より堅牢で安全なアプリケーションを実現できます。