
send v4.1.1
نسخة Fork من وحدة send module للتعامل مع CVE-2017-20165
@fastify/send
Send هي مكتبة لدفق الملفات من نظام الملفات كاستجابة HTTP تدعم الاستجابات الجزئية (النطاقات)، والتفاوض المشروط بـ GET (If-Match، If-Unmodified-Since، If-None-Match، If-Modified-Since)، وتغطية اختبار عالية، وأحداث دقيقة يمكن الاستفادة منها لاتخاذ الإجراءات المناسبة في تطبيقك أو إطار العمل الخاص بك.
التثبيت
هذه وحدة Node.js متاحة عبر npm registry. يتم التثبيت باستخدام الأمر npm install:
$ npm install @fastify/send
TypeScript
يجب استخدام @types/mime@3 إذا كنت ترغب في استخدام TypeScript؛
@types/mime@4 أزال أنواع mime.
$ npm install -D @types/mime@3
API
const send = require('@fastify/send')
send(req, path, [options])
توفر statusCode، headers، و stream للمسار المحدد لإرسالها إلى res. req هو طلب HTTP الخاص بـ Node.js و path هو مسار مرمّز بعناوين URL للإرسال (مرمّز، وليس مسار نظام الملفات الفعلي).
الخيارات
acceptRanges
تفعيل أو تعطيل قبول الطلبات ذات النطاق، القيمة الافتراضية هي true.
تعطيل هذا الخيار لن يرسل Accept-Ranges وسيتجاهل محتوى رأس الطلب Range.
cacheControl
تفعيل أو تعطيل تعيين رأس الاستجابة Cache-Control، القيمة الافتراضية هي true.
تعطيل هذا الخيار سيتجاهل خيارات immutable و maxAge.
contentType
بشكل افتراضي، تستخدم هذه المكتبة وحدة mime لتعيين Content-Type للاستجابة بناءً على امتداد الملف المطلوب.
لتعطيل هذه الوظيفة، قم بتعيين contentType إلى false.
سيحتاج رأس Content-Type إلى التعيين يدويًا إذا تم تعطيله.
dotfiles
تحديد كيفية معالجة "ملفات النقطة" عند مواجهتها. ملف النقطة هو ملف أو دليل يبدأ بنقطة ("."). لاحظ أن هذا الفحص يتم على المسار نفسه دون التحقق من وجود المسار على القرص. إذا تم تحديد root، يتم فحص ملفات النقطة الموجودة فوق الجذر فقط (أي أن الجذر نفسه يمكن أن يكون داخل ملف نقطة عند تعيينه على "deny").
'allow'لا توجد معاملة خاصة لملفات النقطة.'deny'إرسال 403 لأي طلب لملف نقطة.'ignore'التظاهر بأن ملف النقطة غير موجود وإرجاع 404.
القيمة الافتراضية مشابهة لـ 'ignore'، مع استثناء أن هذه القيمة الافتراضية لن تتجاهل الملفات داخل دليل يبدأ بنقطة، وذلك للتوافق مع الإصدارات السابقة.
end
إزاحة البايت التي ينتهي عندها الدفق، القيمة الافتراضية هي طول الملف ناقص 1. النهاية شاملة في الدفق، مما يعني أن end: 3 ستضم البايت الرابع في الدفق.
etag
تفعيل أو تعطيل توليد etag، القيمة الافتراضية هي true.
extensions
إذا لم يكن الملف المحدد موجودًا، حاول إضافة أحد الامتدادات المحددة، بالترتيب المحدد. افتراضيًا، هذا معطّل (مضبوط على false). قيمة مثال ستخدم ملفات HTML بدون امتداد: ['html', 'htm']. يتم تخطي هذا إذا كان الملف المطلوب يحتوي بالفعل على امتداد.
immutable
تفعيل أو تعطيل التوجيه immutable في رأس الاستجابة Cache-Control، القيمة الافتراضية هي false. إذا تم تعيينها إلى true، يجب أيضًا تحديد خيار maxAge لتمكين التخزين المؤقت. سيمنع التوجيه immutable العملاء المدعومين من إجراء طلبات شرطية خلال فترة خيار maxAge للتحقق مما إذا كان الملف قد تغير.
index
بشكل افتراضي، يدعم send ملفات "index.html"، لتعطيل ذلك قم بتعيين false أو لتوفير فهرس جديد قم بتمرير سلسلة نصية أو مصفوفة بالترتيب المفضل.
lastModified
تفعيل أو تعطيل رأس Last-Modified، القيمة الافتراضية هي true. يستخدم قيمة التعديل الأخيرة لنظام الملفات.
maxAge
توفير حد أقصى للعمر بالمللي ثانية للتخزين المؤقت HTTP، القيمة الافتراضية هي 0. يمكن أن يكون هذا أيضًا سلسلة نصية مقبولة بواسطة وحدة ms.
maxContentRangeChunkSize
تحديد الحد الأقصى لحجم محتوى الاستجابة، القيمة الافتراضية هي حجم الملف بالكامل. سيتم استخدام هذا عندما يكون acceptRanges صحيحًا.
root
خدمة الملفات نسبيًا إلى path.
start
إزاحة البايت التي يبدأ عندها الدفق، القيمة الافتراضية هي 0. البداية شاملة، مما يعني أن start: 2 ستضم البايت الثالث في الدفق.
highWaterMark
عند توفيره، يعيّن هذا الخيار الحد الأقصى لعدد البايتات التي سيحتفظ بها المخزن المؤقت الداخلي قبل إيقاف القراءات من المورد الأساسي. إذا حذفت هذا الخيار (أو مررت undefined)، فإن Node.js يعود إلى الإعداد الافتراضي المدمج للتيارات الثنائية القابلة للقراءة.
.mime
التصدير mime هو المثيل العام لوحدة mime npm.
يستخدم هذا لتكوين أنواع MIME المرتبطة بامتدادات الملفات بالإضافة إلى خيارات أخرى لكيفية حل نوع MIME لملف (مثل النوع الافتراضي لاستخدامه لامتداد ملف غير معروف).
التخزين المؤقت
لا يقوم بـ التخزين المؤقت الداخلي، يجب عليك استخدام وكيل عكسي للتخزين المؤقت مثل Varnish لهذا، أو تلك الأشياء الفاخرة التي تسمى CDNs. إذا كان تطبيقك صغيرًا بما يكفي لاستفادته من التخزين المؤقت في الذاكرة على عقدة واحدة، فهو صغير بما يكفي لعدم الحاجة إلى التخزين المؤقت على الإطلاق ;).
التصحيح
لتفعيل إخراج debug()، قم بتصدير NODE_DEBUG:
$ NODE_DEBUG=send node app
تشغيل الاختبارات
$ npm install
$ npm test
أمثلة
خدمة ملف معين
هذا المثال البسيط سيرسل ملفًا معينًا لجميع الطلبات.
const http = require('node:http')
const send = require('send')
const server = http.createServer(async function onRequest (req, res) {
const { statusCode, headers, stream } = await send(req, '/path/to/index.html')
res.writeHead(statusCode, headers)
stream.pipe(res)
})
server.listen(3000)
خدمة جميع الملفات من دليل
هذا المثال البسيط سيخدم جميع الملفات في دليل معين كمستوى أعلى. على سبيل المثال، طلب GET /foo.txt سيرسل /www/public/foo.txt.
const http = require('node:http')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
const server = http.createServer(async function onRequest (req, res) {
const { statusCode, headers, stream } = await send(req, parseUrl(req).pathname, { root: '/www/public' })
res.writeHead(statusCode, headers)
stream.pipe(res)
})
server.listen(3000)
أنواع الملفات المخصصة
const http = require('node:http')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
// تعيين الأنواع غير المعروفة افتراضيًا إلى text/plain
send.mime.default_type = 'text/plain'
// إضافة نوع مخصص
send.mime.define({
'application/x-my-type': ['x-mt', 'x-mtt']
})
const server = http.createServer(function onRequest (req, res) {
const { statusCode, headers, stream } = await send(req, parseUrl(req).pathname, { root: '/www/public' })
res.writeHead(statusCode, headers)
stream.pipe(res)
})
server.listen(3000)
عرض فهرس الدليل المخصص
هذا مثال على خدمة هيكل من الدلائل مع وظيفة مخصصة لعرض قائمة بالدليل.
const http = require('node:http')
const fs = require('node:fs')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
// نقل الملفات العشوائية من داخل /www/example.com/public/*
// مع معالج مخصص لعرض قائمة الدليل
const server = http.createServer(async function onRequest (req, res) {
const { statusCode, headers, stream, type, metadata } = await send(req, parseUrl(req).pathname, { index: false, root: '/www/public' })
if(type === 'directory') {
// الحصول على قائمة الدليل
const list = await readdir(metadata.path)
// عرض فهرس للدليل
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' })
res.end(list.join('\n') + '\n')
} else {
res.writeHead(statusCode, headers)
stream.pipe(res)
}
})
server.listen(3000)
الخدمة من دليل جذر مع معالجة أخطاء مخصصة
const http = require('node:http')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
const server = http.createServer(async function onRequest (req, res) {
// نقل الملفات العشوائية من داخل
// /www/example.com/public/*
const { statusCode, headers, stream, type, metadata } = await send(req, parseUrl(req).pathname, { root: '/www/public' })
switch (type) {
case 'directory': {
// منطق معالجة الدليل المخصص لديك:
res.writeHead(301, {
'Location': metadata.requestPath + '/'
})
res.end('جاري إعادة التوجيه إلى ' + metadata.requestPath + '/')
break
}
case 'error': {
// منطق معالجة الأخطاء المخصص لديك:
res.writeHead(metadata.error.status ?? 500, {})
res.end(metadata.error.message)
break
}
default: {
// الرؤوس المخصصة لديك
// خدمة جميع الملفات للتحميل
res.setHeader('Content-Disposition', 'attachment')
res.writeHead(statusCode, headers)
stream.pipe(res)
}
}
})
server.listen(3000)
الترخيص
مرخص بموجب MIT.