Skip to content

ينفذ Bun معيار WHATWG fetch، مع بعض الامتدادات لتلبية احتياجات JavaScript من جانب الخادم.

ينفذ Bun أيضًا node:http، لكن fetch موصى به بدلاً من ذلك.

إرسال طلب HTTP

لإرسال طلب HTTP، استخدم fetch

ts
const response = await fetch("http://example.com");

console.log(response.status); // => 200

const text = await response.text(); // أو response.json()، response.formData()، إلخ.

يعمل fetch أيضًا مع عناوين HTTPS.

ts
const response = await fetch("https://example.com");

يمكنك أيضًا تمرير كائن Request إلى fetch.

ts
const request = new Request("http://example.com", {
  method: "POST",
  body: "Hello, world!",
});

const response = await fetch(request);

إرسال طلب POST

لإرسال طلب POST، مرر كائنًا مع تعيين خاصية method إلى "POST".

ts
const response = await fetch("http://example.com", {
  method: "POST",
  body: "Hello, world!",
});

يمكن أن يكون body سلسلة أو كائن FormData أو ArrayBuffer أو Blob، وأكثر من ذلك. راجع توثيق MDN لمزيد من المعلومات.

بروكسي الطلبات

لبروكسي طلب، مرر كائنًا مع تعيين خاصية proxy إلى سلسلة URL:

ts
const response = await fetch("http://example.com", {
  proxy: "http://proxy.com",
});

يمكنك أيضًا استخدام تنسيق كائن لإرسال رؤوس مخصصة إلى خادم الوكيل:

ts
const response = await fetch("http://example.com", {
  proxy: {
    url: "http://proxy.com",
    headers: {
      "Proxy-Authorization": "Bearer my-token",
      "X-Custom-Proxy-Header": "value",
    },
  },
});

يتم إرسال headers مباشرة إلى الوكيل في طلبات CONNECT (لأهداف HTTPS) أو في طلب الوكيل (لأهداف HTTP). إذا قدمت رأس Proxy-Authorization، فإنه يتجاوز أي بيانات اعتماد في عنوان URL للوكيل.

رؤوس مخصصة

لتعيين رؤوس مخصصة، مرر كائنًا مع تعيين خاصية headers إلى كائن.

ts
const response = await fetch("http://example.com", {
  headers: {
    "X-Custom-Header": "value",
  },
});

يمكنك أيضًا تعيين الرؤوس باستخدام كائن Headers.

ts
const headers = new Headers();
headers.append("X-Custom-Header", "value");

const response = await fetch("http://example.com", {
  headers,
});

أجوبة الاستجابة

لقراءة جسم الاستجابة، استخدم إحدى الطرق التالية:

  • response.text(): Promise<string>: يرجع promise يحل مع جسم الاستجابة كسلسلة.
  • response.json(): Promise<any>: يرجع promise يحل مع جسم الاستجابة ككائن JSON.
  • response.formData(): Promise<FormData>: يرجع promise يحل مع جسم الاستجابة ككائن FormData.
  • response.bytes(): Promise<Uint8Array>: يرجع promise يحل مع جسم الاستجابة كـ Uint8Array.
  • response.arrayBuffer(): Promise<ArrayBuffer>: يرجع promise يحل مع جسم الاستجابة كـ ArrayBuffer.
  • response.blob(): Promise<Blob>: يرجع promise يحل مع جسم الاستجابة كـ Blob.

تدفق أجوبة الاستجابة

يمكنك استخدام iterators غير المتزامنة لتدفق جسم الاستجابة.

ts
const response = await fetch("http://example.com");

for await (const chunk of response.body) {
  console.log(chunk);
}

يمكنك أيضًا الوصول بشكل مباشر إلى كائن ReadableStream.

ts
const response = await fetch("http://example.com");

const stream = response.body;

const reader = stream.getReader();
const { value, done } = await reader.read();

تدفق أجوبة الطلبات

يمكنك أيضًا تدفق البيانات في أجوبة الطلبات باستخدام ReadableStream:

ts
const stream = new ReadableStream({
  start(controller) {
    controller.enqueue("Hello");
    controller.enqueue(" ");
    controller.enqueue("World");
    controller.close();
  },
});

const response = await fetch("http://example.com", {
  method: "POST",
  body: stream,
});

عند استخدام streams مع HTTP(S):

  • يتم تدفق البيانات مباشرة إلى الشبكة بدون تخزين الجسم بالكامل في الذاكرة
  • إذا فُقد الاتصال، يُلغى الـ stream
  • لا يتم تعيين رأس Content-Length تلقائيًا ما لم يكن للـ stream حجم معروف

عند استخدام streams مع S3:

  • لطلبات PUT/POST، يستخدم Bun تلقائيًا تحميل متعدد الأجزاء
  • يتم استهلاك الـ stream في قطع وتحميلها بشكل متوازٍ
  • يمكن مراقبة التقدم من خلال خيارات S3

جلب URL مع مهلة

لجلب URL مع مهلة، استخدم AbortSignal.timeout:

ts
const response = await fetch("http://example.com", {
  signal: AbortSignal.timeout(1000),
});

إلغاء طلب

لإلغاء طلب، استخدم AbortController:

ts
const controller = new AbortController();

const response = await fetch("http://example.com", {
  signal: controller.signal,
});

controller.abort();

مقابس مجال Unix

لجلب URL باستخدام مقبس مجال Unix، استخدم خيار unix: string:

ts
const response = await fetch("https://hostname/a/path", {
  unix: "/var/run/path/to/unix.sock",
  method: "POST",
  body: JSON.stringify({ message: "Hello from Bun!" }),
  headers: {
    "Content-Type": "application/json",
  },
});

TLS

لاستخدام شهادة عميل، استخدم خيار tls:

ts
await fetch("https://example.com", {
  tls: {
    key: Bun.file("/path/to/key.pem"),
    cert: Bun.file("/path/to/cert.pem"),
    // ca: [Bun.file("/path/to/ca.pem")],
  },
});

التحقق من TLS مخصص

لتخصيص التحقق من TLS، استخدم خيار checkServerIdentity في tls

ts
await fetch("https://example.com", {
  tls: {
    checkServerIdentity: (hostname, peerCertificate) => {
      // إرجاع Error إذا كانت الشهادة غير صالحة
    },
  },
});

هذا مشابه لكيفية عمله في وحدة net في Node.

تعطيل التحقق من TLS

لتعطيل التحقق من TLS، اضبط rejectUnauthorized إلى false:

ts
await fetch("https://example.com", {
  tls: {
    rejectUnauthorized: false,
  },
});

هذا مفيد بشكل خاص لتجنب أخطاء SSL عند استخدام شهادات ذاتية التوقيع، لكن هذا يعطل التحقق من TLS ويجب استخدامه بحذر.

خيارات الطلب

بالإضافة إلى خيارات fetch القياسية، يوفر Bun العديد من الامتدادات:

ts
const response = await fetch("http://example.com", {
  // التحكم في فك ضغط الاستجابة التلقائي (الافتراضي: true)
  // يدعم gzip، deflate، brotli (br)، و zstd
  decompress: true,

  // تعطيل إعادة استخدام الاتصال لهذا الطلب
  keepalive: false,

  // مستوى تسجيل التصحيح
  verbose: true, // أو "curl" لمخرجات أكثر تفصيلاً
});

دعم البروتوكول

بالإضافة إلى HTTP(S)، يدعم fetch في Bun العديد من البروتوكولات الإضافية:

عناوين S3 - s3://

يدعم Bun الجلب من دلاء S3 مباشرة.

ts
// استخدام متغيرات البيئة للبيانات الاعتمادية
const response = await fetch("s3://my-bucket/path/to/object");

// أو تمرير البيانات الاعتمادية بشكل صريح
const response = await fetch("s3://my-bucket/path/to/object", {
  s3: {
    accessKeyId: "YOUR_ACCESS_KEY",
    secretAccessKey: "YOUR_SECRET_KEY",
    region: "us-east-1",
  },
});

ملاحظة: فقط طريقتا PUT و POST تدعمان أجوبة الطلبات عند استخدام S3. للتحميلات، يستخدم Bun تلقائيًا تحميل متعدد الأجزاء للأجوبة المتدفقة.

يمكنك قراءة المزيد عن دعم Bun لـ S3 في توثيق S3.

عناوين الملفات - file://

يمكنك جلب ملفات محلية باستخدام بروتوكول file::

ts
const response = await fetch("file:///path/to/file.txt");
const text = await response.text();

على Windows، يتم تطبيع المسارات تلقائيًا:

ts
// كلاهما يعمل على Windows
const response = await fetch("file:///C:/path/to/file.txt");
const response2 = await fetch("file:///c:/path\\to/file.txt");

عناوين البيانات - data:

يدعم Bun مخطط عنوان data::

ts
const response = await fetch("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==");
const text = await response.text(); // "Hello, World!"

عناوين Blob - blob:

يمكنك جلب blobs باستخدام عناوين تم إنشاؤها بواسطة URL.createObjectURL():

ts
const blob = new Blob(["Hello, World!"], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const response = await fetch(url);

معالجة الأخطاء

يتضمن تنفيذ fetch في Bun العديد من حالات الأخطاء المحددة:

  • استخدام جسم طلب مع طرق GET/HEAD سيرمي خطأ (وهو متوقع لواجهة برمجة تطبيقات fetch)
  • محاولة استخدام كلا خياري proxy و unix معًا سيرمي خطأ
  • فشل التحقق من شهادة TLS عندما يكون rejectUnauthorized true (أو undefined)
  • قد ترمي عمليات S3 أخطاء محددة تتعلق بالمصادقة أو الأذونات

معالجة Content-Type

يضبط Bun تلقائيًا رأس Content-Type لأجوبة الطلبات عندما لا يتم توفيره صراحة:

  • لكائنات Blob، يستخدم type الخاص بالـ blob
  • لـ FormData، يضبط حدود multipart المناسبة

التصحيح

للمساعدة في التصحيح، يمكنك تمرير verbose: true إلى fetch:

ts
const response = await fetch("http://example.com", {
  verbose: true,
});

سيطبع هذا رؤوس الطلب والاستجابة إلى طرفيتك:

sh
[fetch] > HTTP/1.1 GET http://example.com/
[fetch] > Connection: keep-alive
[fetch] > User-Agent: Bun/1.3.3
[fetch] > Accept: */*
[fetch] > Host: example.com
[fetch] > Accept-Encoding: gzip, deflate, br, zstd

[fetch] < 200 OK
[fetch] < Content-Encoding: gzip
[fetch] < Age: 201555
[fetch] < Cache-Control: max-age=604800
[fetch] < Content-Type: text/html; charset=UTF-8
[fetch] < Date: Sun, 21 Jul 2024 02:41:14 GMT
[fetch] < Etag: "3147526947+gzip"
[fetch] < Expires: Sun, 28 Jul 2024 02:41:14 GMT
[fetch] < Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
[fetch] < Server: ECAcc (sac/254F)
[fetch] < Vary: Accept-Encoding
[fetch] < X-Cache: HIT
[fetch] < Content-Length: 648

ملاحظة: verbose: boolean ليس جزءًا من واجهة برمجة تطبيقات fetch القياسية للويب وهو خاص بـ Bun.

الأداء

قبل إرسال طلب HTTP، يجب إجراء بحث DNS. يمكن أن يستغرق هذا وقتًا طويلاً، خاصة إذا كان خادم DNS بطيئًا أو اتصال الشبكة ضعيفًا.

بعد بحث DNS، يجب توصيل مقبس TCP وقد تحتاج إلى إجراء مصافحة TLS. يمكن أن يستغرق هذا أيضًا وقتًا طويلاً.

بعد اكتمال الطلب، يمكن أن يستغرق استهلاك جسم الاستجابة أيضًا وقتًا طويلاً والذاكرة.

في كل خطوة من الخطوات، يوفر Bun واجهات برمجة تطبيقات لمساعدتك في تحسين أداء تطبيقك.

الجلب المسبق لـ DNS

للجلب المسبق لإدخال DNS، يمكنك استخدام واجهة برمجة تطبيقات dns.prefetch. واجهة برمجة التطبيقات هذه مفيدة عندما تعرف أنك ستحتاج للاتصال بمضيف قريبًا وتريد تجنب بحث DNS الأولي.

ts
import { dns } from "bun";

dns.prefetch("bun.com");

التخزين المؤقت لـ DNS

افتراضيًا، يخزن Bun ويهدر استعلامات DNS في الذاكرة لمدة تصل إلى 30 ثانية. يمكنك عرض إحصائيات التخزين المؤقت عن طريق استدعاء dns.getCacheStats():

لمعرفة المزيد حول التخزين المؤقت لـ DNS في Bun، راجع توثيق التخزين المؤقت لـ DNS.

الاتصال المسبق بمضيف

للاتصال المسبق بمضيف، يمكنك استخدام واجهة برمجة تطبيقات fetch.preconnect. واجهة برمجة التطبيقات هذه مفيدة عندما تعرف أنك ستحتاج للاتصال بمضيف قريبًا وتريد بدء بحث DNS الأولي، واتصال مقبس TCP، ومصافحة TLS مبكرًا.

ts
import { fetch } from "bun";

fetch.preconnect("https://bun.com");

ملاحظة: استدعاء fetch مباشرة بعد fetch.preconnect لن يجعل طلبك أسرع. الاتصال المسبق يساعد فقط إذا كنت تعرف أنك ستحتاج للاتصال بمضيف قريبًا، لكنك لست مستعدًا لإجراء الطلب بعد.

الاتصال المسبق عند بدء التشغيل

للاتصال المسبق بمضيف عند بدء التشغيل، يمكنك تمرير --fetch-preconnect:

sh
bun --fetch-preconnect https://bun.com ./my-script.ts

هذا يشبه إلى حد ما <link rel="preconnect"> في HTML.

هذه الميزة غير منفذة على Windows بعد. إذا كنت مهتمًا باستخدام هذه الميزة على Windows، يرجى تقديم مشكلة ويمكننا تنفيذ الدعم لها على Windows.

تجميع الاتصالات و HTTP keep-alive

يعيد Bun استخدام الاتصالات لنفس المضيف تلقائيًا. هذا معروف بتجميع الاتصالات. يمكن أن يقلل هذا بشكل كبير من الوقت المستغرق لإنشاء اتصال. لا تحتاج إلى فعل أي شيء لتفعيل هذا؛ إنه تلقائي.

حد الاتصال المتزامن

افتراضيًا، يحدد Bun الحد الأقصى لعدد طلبات fetch المتزامنة إلى 256. نفعل هذا لعدة أسباب:

  • يحسن استقرار النظام العام. أنظمة التشغيل لديها حد أعلى لعدد مقابس TCP المفتوحة المتزامنة، عادة في الآلاف المنخفضة. الاقتراب من هذا الحد يتسبب في تصرف كمبيوترك بالكامل بشكل غريب. تتعطل التطبيقات وتنهار.
  • يشجع إعادة استخدام اتصال HTTP Keep-Alive. لطلبات HTTP قصيرة العمر، غالبًا ما تكون أبطأ خطوة هي إعداد الاتصال الأولي. إعادة استخدام الاتصالات يمكن أن توفر الكثير من الوقت.

عند تجاوز الحد، يتم وضع الطلبات في قائمة الانتظار وإرسالها بمجرد انتهاء الطلب التالي.

يمكنك زيادة الحد الأقصى لعدد الاتصالات المتزامنة عبر متغير البيئة BUN_CONFIG_MAX_HTTP_REQUESTS:

sh
BUN_CONFIG_MAX_HTTP_REQUESTS=512 bun ./my-script.ts

القيمة القصوى لهذا الحد محددة حاليًا بـ 65,336. رقم المنفذ الأقصى هو 65,535، لذا من الصعب جدًا على أي كمبيوتر واحد تجاوز هذا الحد.

تخزين الاستجابة المؤقت

يبذل Bun قصارى جهده لتحسين أداء قراءة جسم الاستجابة. أسرع طريقة لقراءة جسم الاستجابة هي استخدام إحدى هذه الطرق:

  • response.text(): Promise<string>
  • response.json(): Promise<any>
  • response.formData(): Promise<FormData>
  • response.bytes(): Promise<Uint8Array>
  • response.arrayBuffer(): Promise<ArrayBuffer>
  • response.blob(): Promise<Blob>

يمكنك أيضًا استخدام Bun.write لكتابة جسم الاستجابة إلى ملف على القرص:

ts
import { write } from "bun";

await write("output.txt", response);

تفاصيل التنفيذ

  • تجميع الاتصالات مفعل افتراضيًا لكن يمكن تعطيله لكل طلب مع keepalive: false. يمكن أيضًا استخدام رأس "Connection: close" لتعطيل keep-alive.
  • تحميلات الملفات الكبيرة محسنة باستخدام استدعاء نظام sendfile الخاص بنظام التشغيل في ظل ظروف محددة:
    • يجب أن يكون الملف أكبر من 32KB
    • يجب ألا يستخدم الطلب وكيلًا
    • على macOS، فقط الملفات العادية (وليس الأنابيب أو المقابس أو الأجهزة) يمكنها استخدام sendfile
    • عندما لا تتحقق هذه الشروط، أو عند استخدام S3/تحميلات متدفقة، يعود Bun إلى قراءة الملف إلى الذاكرة
    • هذا التحسين فعال بشكل خاص لطلبات HTTP (وليس HTTPS) حيث يمكن إرسال الملف مباشرة من النواة إلى مكدس الشبكة
  • عمليات S3 تتعامل تلقائيًا مع توقيع الطلبات ودمج رؤوس المصادقة

ملاحظة: العديد من هذه الميزات هي امتدادات خاصة بـ Bun لواجهة برمجة تطبيقات fetch القياسية.

Bun بواسطة www.bunjs.com.cn تحرير