Πώς να χρησιμοποιείτε σωστά τους συνδέσμους POST

Στις εφαρμογές ιστού, ειδικά στις διαχειριστικές διεπαφές, θα πρέπει να αποτελεί βασικό κανόνα ότι οι ενέργειες που αλλάζουν την κατάσταση του διακομιστή δεν θα πρέπει να εκτελούνται μέσω της μεθόδου HTTP GET. Όπως υποδηλώνει το όνομα της μεθόδου, η GET θα πρέπει να χρησιμοποιείται μόνο για την ανάκτηση δεδομένων και όχι για την αλλαγή τους. Για ενέργειες όπως η διαγραφή εγγραφών, είναι καταλληλότερο να χρησιμοποιείται η μέθοδος POST. Αν και το ιδανικό θα ήταν να χρησιμοποιείται η μέθοδος DELETE, αυτή δεν μπορεί να κληθεί χωρίς JavaScript, γι' αυτό και χρησιμοποιείται ιστορικά η μέθοδος POST.

Πώς να το κάνετε στην πράξη; Χρησιμοποιήστε αυτό το απλό τέχνασμα. Στην αρχή του προτύπου σας, δημιουργήστε μια βοηθητική φόρμα με το αναγνωριστικό postForm, την οποία στη συνέχεια θα χρησιμοποιήσετε για τα κουμπιά διαγραφής:

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

Με αυτή τη φόρμα, μπορείτε να χρησιμοποιήσετε ένα <button> αντί της κλασικής <a> συνδέσμου, ο οποίος μπορεί να τροποποιηθεί οπτικά ώστε να μοιάζει με κανονικό σύνδεσμο. Για παράδειγμα, το πλαίσιο Bootstrap CSS προσφέρει τις κλάσεις 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] attribute:

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 για ενέργειες που αλλάζουν κατάσταση, επιτυγχάνετε μια πιο ισχυρή και ασφαλή εφαρμογή.