السيرفر · فصل ١٢

جزر السيرفر والـ Actions والجلسة

server:defer · actions · sessions · fallback
🎯 الهدف: تخلّي حتة من صفحة ثابتة تتجدد لوحدها، وتستقبل فورم بنوع آمن، وتفتكر الزائر بين الطلبات.

جزيرة سيرفر

صفحة المنيو كلها HTML جاهز، وصندوق “طلباتك النهارده” بيتغير لكل زائر. server:defer على مكوّن Astro يأجّل الحتة دي: الصفحة تطلع فورًا، والحتة تتجاب بعدها بطلب منفصل للسيرفر، وترجع HTML مش جافاسكربت إطار.

src/pages/menu.astro
---import Orders from "../components/Orders.astro";---<h1>المنيو</h1><Orders server:defer>  <p slot="fallback">بنجيب طلباتك…</p></Orders>

محتاج adapter، لأن الحتة بتترندر عند الطلب حتى لو باقي الصفحة ثابت. المحتوى الاحتياطي في slot="fallback" يظهر لحد ما الرد يوصل.

الـ props بتعدّي في رابط الطلب مشفّرة. خلّيها صغيرة (رقم تعريف، مش مصفوفة المنيو كلها). المتصفح بيكاش طلبات GET، فتقدر تحط Cache-Control على الرد.

جزيرة سيرفر = HTML متأخر. جزيرة client:* = جافاسكربت في المتصفح. متخلّطش الاتنين.

Actions

الـ endpoint بيديك Response وتكتب التحقق بنفسك. الـ Action دالة سيرفر بنوع: الدخل يتتحقق بـ Zod، والعميل والصفحة يشوفوا نفس الشكل.

src/actions/index.ts
import { defineAction } from "astro:actions";import { z } from "astro/zod";export const server = {  order: defineAction({    accept: "form",    input: z.object({      dish: z.string().min(1),      qty: z.number().int().min(1).max(10),    }),    handler: async (input) => {      return { id: "A1", dish: input.dish, qty: input.qty };    },  }),};

فورم HTML يقدر يبعت للأكشن من غير جافاسكربت. من العميل، actions.order({ dish, qty }) ترجّع data أو error. أسماء المساعدين (getActionResult و isInputError) اتظبطت عبر النسخ، فارجع لدليل الـ Actions وأنت بتوصل الصفحة بنتيجة الفورم.

الصلاحيات والحد من التكرار مكانهم جوّه الـ handler أو في middleware بـ getActionContext من astro:actions. متسيبش أكشن يكتب في قاعدة من غير ما يعرف مين الطالب.

نمط ثابت بعد الفورم: POST ثم تحويل ثم GET، عشان التحديث من المتصفح مايعيدش الإرسال. الجلسة هي اللي بتشيل نتيجة الأكشن بعد التحويل. محتاج مخزن جلسات من الـ adapter.

الجلسة

Astro.session مخزن على السيرفر مربوط بالزائر، مش كوكي فيه الداتا كلها. الكوكي غالبًا مجرد معرّف.

src/pages/cart.astro
---export const prerender = false;const cart = (await Astro.session?.get("cart")) ?? [];---<p>في السلة {cart.length} حاجة</p>

الـ adapter بيجهّز المخزن (على Netlify مثلًا Blobs). تقدر تبدّل الدرايفر من إعداد session في الكونفج. لو مش هتستخدم جلسات، session: false يشيلها من الحزمة.

الجلسة بتتعمل أول ما تقرأها أو تكتبها، وبتتحفظ في آخر الطلب. متحطّش فيها ملفات ولا كائنات ضخمة.

خلّصت الفصل لما

🧠 اختبر نفسك
١) server:defer بينزّل React للزائر؟
لأ. بيرجّع HTML من السيرفر بعد التحميل.
٢) جزيرة سيرفر على موقع ثابت خالص من غير adapter؟
مش هتشتغل. الحتة دي عند الطلب.
٣) ليه POST ثم redirect ثم GET بعد الفورم؟
عشان تحديث الصفحة مايعيدش إرسال الطلب.