Khi mua hàng online, bạn đã bao giờ có suy nghĩ: "Đặt 1 mà được giao 4, chắc tính mở sạp bán hàng online luôn quá!" Rất tiếc là đã nhận 4 thì phải...trả tiền cho cả 4 chứ không có chuyện "miễn phí"!
Trong quá trình "vọc" PHP. Bạn tạo form.
- Tên
- Số điện thoại
Người dùng bấm:
Submit
PHP báo:
Lưu thành công
Trong một buổi sáng đẹp trời, mới ăn một tô phở tái nạm gầu tuyệt vời, làm ly cà phê thơm phức, người dùng thấy vui.
Bèn nhấn: F5
PHP:
Lưu thành công
lần nữa.
Database:
- Nguyễn Văn A
- Nguyễn Văn A
Hơi căng thẳng, anh ấy bèn...thử... tiếp tục: F5
Database:
- Nguyễn Văn A
- Nguyễn Văn A
- Nguyễn Văn A
Nếu đây là đơn hàng:
- 1 đơn
- 2 đơn
- 3 đơn
thì "khổ chủ" bắt đầu thấy hơi run...
Redirect sau submit là gì?
Redirect sau submit là kỹ thuật giúp:
- tránh gửi lại form nhiều lần
- tránh dữ liệu bị insert trùng
- tránh lỗi refresh (F5)
- cải thiện trải nghiệm người dùng
Trong PHP, kỹ thuật phổ biến nhất là:
POST
↓
Process
↓
Redirect
↓
GET
Được gọi là:
PRG
(Post Redirect Get)
Ví dụ đau lòng, không muốn nghe
Form đăng ký:
<?php
if($_SERVER['REQUEST_METHOD']=='POST')
{
mysqli_query($conn,$sql);
echo "Đăng ký thành công";
}
?>Mọi thứ có vẻ ổn.
Cho tới khi người dùng:
F5
Trình duyệt hỏi:
Resubmit form?
Người dùng (vô thức):
Yes
PHP:
INSERT lần nữa
Database: Hả, lại nữa hả bạn hiền!
Ví dụ hơi...thực tế
Hãy tưởng tượng:
Bạn gọi:
1 tô mì Quảng
Nhân viên:
Dạ, có ngay, có ngay....
Ngay khi đó, bạn vô tình nhấn F5...đâu đó trong quán.
Quán mang ra:
- 2 tô
- 3 tô
- 4 tô
Đó chính là duplicate submit.
Vì sao chuyện này xảy ra?
Sau khi submit:
Browser vẫn nhớ:
POST request
Khi F5:
Browser gửi lại POST.
PHP không biết:
- Đây là lần đầu
- hay lần thứ 10
Nó chỉ biết:
Có POST--> thì cứ thế mà xử lý thôi!
Cách lính mới thường làm
<?php
if(isset($_POST['submit']))
{
mysqli_query($conn,$sql);
echo "Success";
}
?>Chạy được.
Nhưng:
F5 = insert lại
Cách đúng
Sau khi xử lý xong:
<?php
if(isset($_POST['submit']))
{
mysqli_query($conn,$sql);
header("Location: success.php");
exit;
}
?>Lúc này:
POST
↓
INSERT
↓
REDIRECT
↓
GET
Khi F5:
GET
không phải:
POST
nữa.
PRG là gì?
PRG:
- Post
- Redirect
- Get
Là mô hình được dùng bởi:
- Shopee
- Lazada
- Amazon
- Gmail
- và gần như mọi website lớn.
Luồng sai
POST
↓
INSERT
↓
Hiển thị kết quả
F5:
POST lại
Luồng đúng
POST
↓
INSERT
↓
REDIRECT
↓
GET
↓
Hiển thị kết quả
F5:
GET lại
Lỗi phổ biến
Quên exit
Ví dụ:
header("Location: success.php");
Nhưng bên dưới vẫn còn code.
Nên dùng:
header("Location: success.php");
exit;Echo trước header
echo "Success";
header("Location: success.php");Header Already Sent
Redirect về chính trang nhưng không thoát
Dễ gây hành vi khó đoán.
Một sự thật...biết rồi, khổ lắm, nói mãi
Rất nhiều website trông có vẻ:
Submit xong hiện kết quả ngay
Nhưng thực tế phía sau là:
POST
↓
REDIRECT
↓
GET
Bạn không nhận ra vì redirect diễn ra trong tích tắc.
Debug kiểu dev "xịn sò"
Kiểm tra Network
Trong DevTools:
- F12
Bạn sẽ thấy:
- POST
- 302 Redirect
- GET
Đó là dấu hiệu PRG hoạt động đúng.
Kiểm tra database
Submit:
1 lần
F5:
không được thêm bản ghi mới
Nếu vẫn thêm:
PRG chưa hoạt động.
Checklist "Chuẩn không cần chỉnh"
- Đã dùng POST chưa?
- Sau INSERT có redirect không?
- Có dùng: exit; không?
- Có echo trước header không?
- F5 có tạo thêm dữ liệu không?
- Đã kiểm tra database chưa?
FAQ nhanh
Redirect sau submit có bắt buộc không?
Không. Nhưng gần như luôn nên dùng.
Redirect có làm mất dữ liệu POST không?
Có. Và đó chính là mục đích.
Làm sao vừa redirect vừa giữ dữ liệu?
Dùng: $_SESSION
Vì sao website lớn ít bị insert trùng?
Vì họ dùng: PRG(Post Redirect Get)
Bạn có thể cũng đang gặp
Login đúng password nhưng vẫn fail
PHP không nhận dữ liệu POST/GET