Как правилно да използваме POST връзки
В уеб приложенията, особено в административните интерфейси, основно правило трябва да бъде, че действията, променящи състоянието на сървъра, не трябва да се извършват чрез HTTP метода GET. Както подсказва името на метода, GET трябва да служи само за получаване на данни, а не за тяхната промяна. За действия като изтриване на записи е по-подходящо да се използва методът POST. Въпреки че идеалният би бил методът DELETE, но той не може да бъде извикан без JavaScript, затова исторически се използва POST.
Как да го направим на практика? Използвайте този прост трик. В
началото на шаблона си създайте помощна форма с идентификатор
postForm
, която след това ще използвате за бутоните за изтриване:
<form method="post" id="postForm"></form>
Благодарение на тази форма можете вместо класическа връзка
<a>
да използвате бутон <button>
, който може да бъде
визуално оформен така, че да изглежда като обикновена връзка. Например
CSS framework 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>
<!-- вместо <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');
}
Този подход не само подобрява сигурността на вашето приложение, но също така допринася за спазването на правилните уеб стандарти и практики. Чрез използването на методи POST за действия, променящи състоянието, ще постигнете по-стабилно и по-сигурно приложение.