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

البيانات والبيئة والـ middleware

fetch · astro:env · endpoints · middleware · locals
🎯 الهدف: تجيب بيانات، تخبّي الأسرار عن المتصفح، وتعدّي كل طلب على middleware قبل الصفحة.

fetch في الـ frontmatter

كود فوق السياج يقدر يعمل await fetch. في صفحة ثابتة النداء بيحصل وقت البناء، والناتج يتطبع في HTML. في صفحة سيرفر النداء بيحصل مع كل طلب.

src/pages/today.astro
---const res = await fetch("https://api.example.com/dish.json");const dish = await res.json();---<p>طبق اليوم: {dish.name}</p>

متعملش كده لبيانات خاصة بزائر على صفحة ثابتة: كل الزوار هياخدوا نفس الـ HTML. ومتحطّش توكن جوه النص اللي هيتبنى.

أسرار ومتغيرات

ملف .env مايترفعش على git. المتغير اللي اسمه هيوصل للمتصفح لازم يبقى واضح إنه عام. المسار المظبوط في Astro دلوقتي مخطط astro:env:

astro.config.mjs
import { defineConfig, envField } from "astro/config";export default defineConfig({  env: {    schema: {      MENU_API: envField.string({ context: "server", access: "secret" }),      PUBLIC_BRAND: envField.string({ context: "client", access: "public" }),    },  },});
src/pages/api/menu.ts
import type { APIRoute } from "astro";import { MENU_API } from "astro:env/server";export const GET: APIRoute = async () => {  const res = await fetch(MENU_API);  return new Response(await res.text(), {    headers: { "content-type": "application/json" },  });};

astro:env/server يتستخدم في سيرفر بس. استيراده من مكوّن هيروح للمتصفح هيفشل البناء، وده الحماية. astro:env/client للمتصفح، وممنوع يكون secret.

import.meta.env بتاع Vite لسه شغال، و PUBLIC_ لسه بتكشف المتغير للعميل لو مشيت على الطريق القديم. الطريق الجديد أوضح لأن النوع والسياق متعلنين في الكونفج.

أي حاجة في حزمة العميل مش سر. اعتبرها متقرأة.

الـ endpoint تاني بس بسياق

الصفحة السابقة عرّفت APIRoute. السياق فيه request و params و cookies و locals و redirect و، لو مظبوط، session و cache. رجّع Response دايمًا. حالة الخطأ new Response("nope", { status: 401 }).

export const prerender = true على endpoint في مشروع سيرفر يخلّيه ملف ثابت. والعكس prerender = false في مشروع ثابت يخلّيه يحتاج adapter.

الـ middleware

src/middleware.ts دالة بتعدّي على الطلبات قبل الصفحة أو الـ endpoint.

src/middleware.ts
import { defineMiddleware } from "astro:middleware";export const onRequest = defineMiddleware(async (context, next) => {  const user = context.cookies.get("user")?.value;  context.locals.user = user;  if (context.url.pathname.startsWith("/kitchen") && !user) {    return context.redirect("/login");  }  return next();});

next() يكمل السلسلة. تقدر تقرا الرد وتعدّل هيدر بعديها. locals كيس بتمرّر بيانات للصفحة في نفس الطلب. عرّف نوعه في src/env.d.ts عشان TypeScript يعرف Astro.locals.user:

src/env.d.ts
declare namespace App {  interface Locals {    user?: string;  }}

أكتر من ملف middleware يترتب بـ sequence من astro:middleware. الترتيب مهم: التحقق قبل التسجيل.

context.rewrite يغيّر الصفحة اللي هتترندر من غير ما يغيّر رابط المتصفح. redirect يبعت الزائر لرابط تاني فعلًا.

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

🧠 اختبر نفسك
١) سر حطيته في صفحة ثابتة وقت البناء. الزائر يشوفه؟
لو اتطبع في HTML أو دخل حزمة العميل، أيوه. السر يفضل على السيرفر.
٢) astro:env/server ينفع في مكوّن client:load؟
لأ. الاستيراد هيفشل لأن السياق سيرفر.
٣) الـ locals عايشة قد إيه؟
طول الطلب الواحد. مش قاعدة بيانات.