Cum să utilizați corect linkurile POST

În aplicațiile web, în special în interfețele administrative, ar trebui să fie o regulă de bază ca acțiunile care modifică starea serverului să nu fie efectuate prin metoda HTTP GET. După cum sugerează și numele metodei, GET ar trebui utilizat doar pentru obținerea datelor, nu pentru modificarea lor. Pentru acțiuni precum ștergerea înregistrărilor, este mai potrivită utilizarea metodei POST. Deși ideală ar fi metoda DELETE, aceasta nu poate fi invocată fără JavaScript, de aceea se folosește istoric POST.

Cum se face acest lucru în practică? Utilizați acest truc simplu. La începutul șablonului, creați un formular auxiliar cu identificatorul postForm, pe care îl veți utiliza ulterior pentru butoanele de ștergere:

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

Datorită acestui formular, puteți utiliza un buton <button> în loc de linkul clasic <a>, care poate fi stilizat vizual pentru a arăta ca un link obișnuit. De exemplu, framework-ul CSS Bootstrap oferă clasele btn btn-link cu care puteți obține ca butonul să nu fie vizual diferit de alte linkuri. Folosind atributul form="postForm", îl legați de formularul pre-pregătit:

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

La click pe buton, se va invoca acum acțiunea delete prin metoda POST. Pentru a asigura că cererile sunt acceptate doar prin metoda POST și de pe același domeniu (ceea ce este o apărare eficientă împotriva atacurilor CSRF), utilizați atributul #[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); // cod ipotetic care șterge înregistrarea
		$this->redirect('default');
	}
}

Atributul există de la Nette Application 3.2 și mai multe despre posibilitățile sale puteți afla pe pagina Cum să utilizați atributul #Requires.

Dacă ați utiliza semnalul handleDelete() în loc de acțiunea actionDelete(), nu este necesar să specificați sameOrigin: true, deoarece semnalele au această protecție setată implicit:

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

Această abordare nu numai că îmbunătățește securitatea aplicației dvs., dar contribuie și la respectarea standardelor și practicilor web corecte. Prin utilizarea metodelor POST pentru acțiunile care modifică starea, veți obține o aplicație mai robustă și mai sigură.