انتقل إلى المحتوى

إنشاء خدمة HTTP

قدّم HTTP من Elide باستخدام معالج fetch أو node:http: التوجيه ومتون JSON والبث المتدفق والملفات الثابتة و TLS والسياقات المتعددة وأطر العمل.

في هذه الصفحة

يقدّم Elide طلبات HTTP من معالج fetch أو من node:http؛ وتبني هذه الصفحة خدمة واحدة بالطريقتين.

طريقتان للتقديم

معالج fetchnode:http
نقطة الدخولexport default { fetch } أو Elide.serve({ fetch })http.createServer(listener).listen(port)
الطلب والاستجابةكائنا الويب Request و ResponseIncomingMessage، ServerResponse
HTTPS و ⁦HTTP/2⁩الخياران cert و keyغير متاح
--contextsنعملا؛ تفشل النسخة الثانية بالخطأ EADDRINUSE
// server.ts
export default {
  port: Number(process.env.PORT ?? 3000),
  fetch(request: Request): Response {
    return new Response("hello\n");
  },
};
// node-server.ts
import { createServer } from "node:http";

const port = Number(process.env.PORT ?? 3000);

createServer((req, res) => {
  res.writeHead(200, { "content-type": "text/plain" });
  res.end("hello\n");
}).listen(port, "127.0.0.1");
elide run server.ts
curl -i http://127.0.0.1:3000/
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
content-length: 6
server: elide
date: Sat, 10 Oct 2026 00:18:12 GMT

hello

يجيب الأمر elide run node-server.ts عن الطلب نفسه مع Transfer-Encoding: chunked و Connection: keep-alive.

العنوان الذي يرتبط به كل أسلوب عندما لا تحدد عنوانًا:

الخادمالعنوان الافتراضي
export default { fetch } تحت elide run127.0.0.1:8080
export default { fetch } تحت elide serve / elide dev127.0.0.1:8080 / 127.0.0.1:3000؛ ويغيّره --host و --port
Elide.serve({ port, fetch })0.0.0.0 على port

المسارات و JSON والبث المتدفق

تتوفر URLPattern و Request.json() و Response.json() ومتون ReadableStream بوصفها كائنات عامة. لهذا الخادم واجهة API واستجابة متدفقة وملفات ثابتة من public/:

// app.ts
import { readFile } from "node:fs/promises";
import { extname, join, normalize } from "node:path";

const users = new URLPattern({ pathname: "/api/users/:id" });
const types: Record<string, string> = {
  ".html": "text/html; charset=utf-8",
  ".css": "text/css",
  ".js": "text/javascript",
};

async function api(request: Request): Promise<Response | null> {
  const url = new URL(request.url);
  const match = users.exec(url);
  if (match && request.method === "GET") {
    return Response.json({ id: match.pathname.groups.id });
  }
  if (url.pathname === "/api/users" && request.method === "POST") {
    const body = await request.json();
    return Response.json({ created: body.name }, { status: 201 });
  }
  if (url.pathname === "/api/ticks") {
    let n = 0;
    const stream = new ReadableStream({
      async pull(controller) {
        controller.enqueue(new TextEncoder().encode(`tick ${++n}\n`));
        await new Promise((r) => setTimeout(r, 200));
        if (n === 3) controller.close();
      },
    });
    return new Response(stream, { headers: { "content-type": "text/plain" } });
  }
  return null;
}

async function file(pathname: string): Promise<Response> {
  const path = join("public", normalize(pathname === "/" ? "/index.html" : pathname));
  try {
    const body = await readFile(path);
    return new Response(body, { headers: { "content-type": types[extname(path)] ?? "application/octet-stream" } });
  } catch {
    return new Response("not found\n", { status: 404 });
  }
}

export default {
  port: Number(process.env.PORT ?? 3000),
  async fetch(request: Request): Promise<Response> {
    return (await api(request)) ?? file(new URL(request.url).pathname);
  },
};
elide run app.ts
curl http://127.0.0.1:3000/api/users/42
curl -X POST -H 'content-type: application/json' -d '{"name":"ada"}' http://127.0.0.1:3000/api/users
curl -N http://127.0.0.1:3000/api/ticks
{"id":"42"}
{"created":"ada"}
tick 1
tick 2
tick 3

يجيب طلب POST بالحالة 201 Created. وتصل النبضات الثلاث بفاصل 200 مللي ثانية. يعيد المسار / الملف public/index.html، ويعيد الملف غير الموجود 404.

تقرأ الواجهة نفسها على node:http المتن باستخدام node:stream/consumers وتبث الاستجابة باستخدام res.write:

// node-app.ts
import { createServer } from "node:http";
import { text } from "node:stream/consumers";

createServer(async (req, res) => {
  if (req.method === "POST" && req.url === "/api/users") {
    const body = JSON.parse(await text(req));
    res.writeHead(201, { "content-type": "application/json" });
    res.end(JSON.stringify({ created: body.name }));
    return;
  }
  if (req.url === "/api/ticks") {
    res.writeHead(200, { "content-type": "text/plain" });
    for (let n = 1; n <= 3; n++) {
      res.write(`tick ${n}\n`);
      await new Promise((r) => setTimeout(r, 200));
    }
    res.end();
    return;
  }
  res.writeHead(404).end();
}).listen(Number(process.env.PORT ?? 3000), "127.0.0.1");

لتقديم الملفات فقط، استخدم elide serve ./public؛ راجع خادم التطوير.

الأخطاء

يجيب معالج fetch الذي يرمي استثناءً أو يُرفض وعده بالحالة 500 Internal Server Error ويواصل العمل. لا يُطبع الخطأ، لذا التقطه وسجّله بنفسك:

curl -i -d 'not json' http://127.0.0.1:3000/api/users
HTTP/1.1 500 Internal Server Error
Content-Type: text/plain; charset=utf-8
content-length: 21
server: elide
date: Sat, 10 Oct 2026 00:34:28 GMT

Internal Server Error

TLS

مرّر سلاسل PEM بوصفها cert و key إلى Elide.serve، أو بوصفها خصائص للكائن المُصدَّر. يجب أن يكون المفتاح بصيغة PKCS#8 غير مشفّرة (BEGIN PRIVATE KEY). يحصل العملاء الذين يعرضون ⁦HTTP/2⁩ عليه.

// tls.ts
import { readFileSync } from "node:fs";

Elide.serve({
  port: Number(process.env.PORT ?? 8443),
  cert: readFileSync("cert.pem", "utf8"),
  key: readFileSync("key.pem", "utf8"),
  fetch(request) {
    return new Response("hello over tls\n");
  },
});
elide run tls.ts
curl -i --cacert cert.pem https://localhost:8443/
HTTP/2 200
content-type: text/plain;charset=UTF-8
content-length: 15
server: elide
date: Sat, 10 Oct 2026 00:18:52 GMT

hello over tls

لا توجد خيارات TLS للأمرين elide serve و elide dev، ولا توجد إعدادات TLS في elide.pkl. ويرمي https.createServer الخطأ التالي:

Error: HTTPS server is not supported in this runtime (no host TLS listener); use http.createServer behind a TLS terminator, or https client APIs.

سياقات متعددة

يشغّل الخيار --contexts=N عدد N من نسخ تطبيق بمعالج fetch على منفذ واحد، على Linux. لكل نسخة حالة وحداتها الخاصة:

// counter.ts
let count = 0;

export default {
  fetch(): Response {
    count += 1;
    return new Response(`${count}\n`);
  },
};
elide serve --no-tui --contexts=4 counter.ts
for i in 1 2 3 4 5 6 7 8; do curl -s http://127.0.0.1:8080/; done
1
1
2
2
3
4
1
2

احفظ الحالة المشتركة في قاعدة بيانات أو خدمة أخرى. يحدد --contexts=auto العدد وفق أنوية المعالج، ويضبطه engine.contexts في elide.pkl لكل مشروع (سياقات المحرك).

أطر العمل

ثبّتها باستخدام elide install --ecosystems=npm.

إطار العملالحالة
Honoيعمل: export default { fetch: app.fetch } أو export default app.
Express 5يعمل التوجيه و res.json و express.raw() وقراءة req يدويًا. ويوقف express.json() و express.text() العملية بالخطأ TypeError: Buffer.isBuffer is not a function.
Fastify 5يفشل عند الاستيراد: Error: No such built-in module: node:http2.
// hono-app.ts
import { Hono } from "hono";

const app = new Hono();
app.get("/users/:id", (c) => c.json({ id: c.req.param("id") }));
app.post("/users", async (c) => c.json({ created: (await c.req.json()).name }, 201));

export default {
  port: Number(process.env.PORT ?? 3000),
  fetch: app.fetch,
};

أمثلة

الخطوات التالية

هل كانت هذه الصفحة مفيدة؟