Kako pravilno uporabljati povezave POST

V spletnih aplikacijah, zlasti v upravnih vmesnikih, bi moralo veljati osnovno pravilo, da se dejanja, ki spreminjajo stanje strežnika, ne smejo izvajati z metodo HTTP GET. Kot pove že ime metode, naj se GET uporablja samo za pridobivanje podatkov in ne za njihovo spreminjanje. Za dejanja, kot je brisanje zapisov, je primerneje uporabiti metodo POST. Čeprav bi bilo idealno uporabiti metodo DELETE, je brez JavaScripta ni mogoče izvesti, zato se v preteklosti uporablja metoda POST.

Kako to storiti v praksi? Uporabite ta preprost trik. Na začetku predloge ustvarite pomožni obrazec z identifikatorjem postForm, ki ga boste nato uporabili za gumbe za brisanje:

<form method="post" id="postForm"></form>

S tem obrazcem lahko uporabite <button> namesto klasičnega <a> povezavo, ki jo lahko vizualno spremenite tako, da je videti kot običajna povezava. Ogrodje Bootstrap CSS na primer ponuja razrede btn btn-link, ki omogočajo, da se gumb vizualno ne razlikuje od drugih povezav. Z uporabo atributa form="postForm" ga povežemo z vnaprej pripravljenim obrazcem:

<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>

Ob kliku na povezavo se zdaj sproži dejanje delete. Če želite zagotoviti, da se zahtevki sprejemajo samo z metodo POST in iz iste domene (kar je učinkovita obramba pred napadi CSRF), uporabite #[Requires] atribut:

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');
	}
}

Atribut je na voljo od različice Nette Application 3.2, več o njegovih zmogljivostih pa lahko izveste na strani Kako uporabljati atribut #Requires.

Če bi namesto akcije actionDelete() uporabili signal handleDelete(), vam ni treba navesti sameOrigin: true, saj imajo signali implicitno nastavljeno to zaščito:

#[Requires(methods: 'POST')]
public function handleDelete(int $id): void
{
	$this->facade->deletePost($id);
	$this->redirect('this');
}

Ta pristop ne izboljša le varnosti vaše aplikacije, temveč prispeva tudi k upoštevanju ustreznih spletnih standardov in praks. Z uporabo metod POST za dejanja, ki spreminjajo stanje, dosežete robustnejšo in varnejšo aplikacijo.