Safe Action: ارسال امن به سرور
لایهای برای فرمها و دکمههایی که به سرور درخواست میزنند. بدون JavaScript، فرم همان فرم معمولی مرورگر است؛ با ماژول action قفل ارسال دوباره، CSRF، Idempotency-Key، مهلت زمانی، تلاش مجدد اختیاری و پیامهای فارسی میگیرد. ماژول action لازم است. نمونههای زیر به یک سرور ساختگی داخل همین صفحه وصلاند.
<form data-safe-action data-validate action="https://demo.bana.test/api/signup" method="post" ui="stack" style="max-inline-size:24rem">
<label ui="field"><span>ایمیل</span><input name="email" type="email" required class="ltr" dir="ltr" placeholder="taken@example.com"><small>برای دیدن خطای سرور «taken» را در ایمیل بنویسید.</small></label>
<label ui="field"><span>نام</span><input name="name" required></label>
<button ui="primary" type="submit">ثبتنام</button>
</form>
<div ui="cluster">
<button ui="danger" data-safe-action="https://demo.bana.test/api/items/7" data-method="delete" data-danger data-confirm="این مورد برای همیشه حذف میشود." data-confirm-ok="حذف" data-retries="2" data-success-message="مورد حذف شد.">حذف (سرور ناپایدار)</button>
<button ui="secondary" data-safe-action="https://demo.bana.test/api/forbidden" data-method="post">عملیات بدون مجوز</button>
</div>
دکمه اول دو بار با خطای ۵۰۳ روبهرو میشود و با data-retries="2" خودکار دوباره تلاش میکند؛ هر سه تلاش یک Idempotency-Key یکسان دارند. دکمه دوم خطای ۴۰۳ میگیرد و پیام فارسی نشان داده میشود. در حین ارسال، دکمه aria-busy میگیرد و ارسال دوباره نادیده گرفته میشود.
| صفت | کار |
|---|---|
| data-safe-action | روی <form> (از action و method خود فرم استفاده میکند) یا <button> (مقدار صفت = نشانی). |
| data-method | متد HTTP برای دکمهها (پیشفرض POST). |
| data-format="json" | بدنه بهصورت JSON؛ پیشفرض urlencoded (و multipart اگر فایل باشد). |
| data-confirm | پنجره تأیید پیش از ارسال؛ با data-danger دکمه تأیید قرمز میشود. |
| data-retries="2" | تلاش مجدد با back-off برای ۵۰۲/۵۰۳/۵۰۴ و خطای شبکه؛ فقط روی GET/PUT/DELETE (برای POST باید در API retryUnsafe بدهید). |
| data-timeout, data-redirect, data-reset, data-success-message | مهلت (میلیثانیه)، مقصد بعد از موفقیت (فقط هممبدأ)، پاککردن فرم و پیام موفقیت. |
پاسخ سرور (JSON): { "message": "...", "errors": { "email": "..." }, "redirect": "/done" }. خطاهای errors زیر فیلد مربوط با aria-invalid و aria-describedby نشان داده میشوند و فوکوس به اولین آنها میرود. رویدادها (حبابشونده): bana:action-start (قابللغو)، -success، -error و -end با e.detail.result.
import { Bana } from "@bana-ui/core";
// 1) CSRF: a <meta name="csrf-token" content="..."> is read automatically
Bana.action.configure({ csrf: { header: "X-CSRF-Token" }, allowOrigins: ["https://api.example.com"] });
// 2) Programmatic call; never throws on HTTP or network errors
const r = await Bana.action.run("/api/items", { method: "post", body: { title: "x" }, timeout: 8000 });
if (!r.ok) console.log(r.status, r.error, r.message); // error: http | network | timeout | blocked | abortedallowOrigins) پذیرفته میشوند و فقط ریدایرکت هممبدأ دنبال میشود.