Як правильно використовувати POST-посилання
У веб-додатках, особливо в адміністративних інтерфейсах, основним правилом має бути те, що дії, які змінюють стан сервера, не повинні виконуватися за допомогою методу HTTP GET. Як випливає з назви методу, GET слід використовувати тільки для отримання даних, а не для їх зміни. Для таких дій, як видалення записів, доцільніше використовувати метод POST. Хоча ідеальним варіантом було б використання методу DELETE, але його неможливо викликати без JavaScript, тому історично використовується POST.
Як це зробити на практиці? Використовуйте цей простий трюк. На
початку вашого шаблону створіть допоміжну форму з ідентифікатором
postForm
, яку ви потім будете використовувати для кнопок
видалення:
<form method="post" id="postForm"></form>
У цій формі ви можете використовувати <button>
замість
класичного <a>
посилання, яке можна візуально модифікувати,
щоб воно виглядало як звичайне. Наприклад, 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}">delete</button>
<!-- instead of <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); // hypothetical code for deleting a record
$this->redirect('default');
}
}
Атрибут доступний з версії Nette Application 3.2, і ви можете дізнатися більше про його можливості на сторінці Як використовувати атрибут #Requires.
Якщо ви використовували сигнал handleDelete()
замість дії
actionDelete()
, то не обов'язково вказувати sameOrigin: true
, оскільки в
сигналах цей захист встановлено неявно:
#[Requires(methods: 'POST')]
public function handleDelete(int $id): void
{
$this->facade->deletePost($id);
$this->redirect('this');
}
Такий підхід не тільки підвищує безпеку вашого додатку, але й сприяє дотриманню належних веб-стандартів і практик. Використовуючи методи POST для дій, що змінюють стан, ви отримуєте більш надійний і безпечний додаток.