شرح AWS S3: كيف ترفع الملفات للـ cloud من تطبيقك
الحوسبة السحابية

شرح AWS S3: كيف ترفع الملفات للـ cloud من تطبيقك

Amazon S3 الخدمة الأشهر لتخزين الملفات في السحابة. تعلّم الإعداد، الرفع من Node.js، والأمان الأساسي.

م
مؤسس LahbabiGuide
4 دقائق قراءة
شارك:

ما هو S3؟

Amazon S3 (Simple Storage Service) خدمة تخزين ملفات على سحابة Amazon. تحفظ أي نوع من الملفات (صور، فيديو، نسخ احتياطية، ملفات عامّة) بأيّ حجم وبسعر منخفض.

لماذا S3 وليس خادمك:

  • لا حدود للسعة (بايلات؟ لا مشكلة)
  • نسخ احتياطية تلقائية (99.999999999% متانة)
  • توزيع عالمي (CDN مع CloudFront)
  • أسعار معقولة ($0.023/GB شهرياً)

المفاهيم

  • Bucket: "مجلد" كبير — يحوي الملفات. اسمه فريد على مستوى العالم
  • Object: الملف نفسه — نص + metadata
  • Key: مسار الملف داخل الـ bucket (مثل images/profile.jpg)
  • Region: المنطقة الجغرافية (us-east-1، eu-west-1، me-south-1 للشرق الأوسط)

إنشاء Bucket

  1. اذهب لـ console.aws.amazon.com/s3
  2. Create bucket
  3. اسم فريد (مثل my-app-uploads-2026)
  4. Region الأقرب لمستخدميك
  5. Block all public access — موصى به، سنستخدم presigned URLs
إعلان

IAM: مستخدم بصلاحيات محدودة

لا تستخدم root account أبداً. أنشئ مستخدماً مخصّصاً:

  1. IAM → Users → Add user
  2. Access type: Access key
  3. Attach policy مثل AmazonS3FullAccess (أو أضيق للإنتاج)
  4. احفظ Access Key ID و Secret Access Key

⚠️ لا ترفع هذه المفاتيح لـ Git أبداً.

الاتصال من Node.js

bash
npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
js
// s3.js
import { S3Client } from "@aws-sdk/client-s3";

export const s3 = new S3Client({
  region: "me-south-1",
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  },
});

export const BUCKET = process.env.S3_BUCKET;

رفع ملف

js
import { PutObjectCommand } from "@aws-sdk/client-s3";
import { readFile } from "node:fs/promises";
import { s3, BUCKET } from "./s3.js";

async function uploadFile(localPath, key) {
  const body = await readFile(localPath);

  await s3.send(new PutObjectCommand({
    Bucket: BUCKET,
    Key: key,
    Body: body,
    ContentType: "image/jpeg",
    CacheControl: "public, max-age=31536000",
  }));

  return `https://${BUCKET}.s3.me-south-1.amazonaws.com/${key}`;
}

// الاستخدام
const url = await uploadFile("./photo.jpg", "uploads/2026/photo.jpg");

رفع من متصفّح: Presigned URLs

الطريقة الأذكى — لا تمرّ الملفات بخادمك، ترفع مباشرة لـ S3.

على الخادم: أنشئ رابطاً مؤقّتاً

js
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { PutObjectCommand } from "@aws-sdk/client-s3";

app.post("/api/upload-url", auth, async (req, res) => {
  const { filename, contentType } = req.body;
  const key = `uploads/${req.user.id}/${Date.now()}-${filename}`;

  const command = new PutObjectCommand({
    Bucket: BUCKET,
    Key: key,
    ContentType: contentType,
  });

  const url = await getSignedUrl(s3, command, { expiresIn: 300 }); // 5 دقائق

  res.json({
    uploadUrl: url,
    finalUrl: `https://${BUCKET}.s3.me-south-1.amazonaws.com/${key}`,
  });
});

على العميل: ارفع مباشرة

js
async function uploadToS3(file) {
  // 1. اطلب presigned URL
  const { uploadUrl, finalUrl } = await fetch("/api/upload-url", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ filename: file.name, contentType: file.type }),
  }).then(r => r.json());

  // 2. ارفع الملف مباشرة لـ S3
  await fetch(uploadUrl, {
    method: "PUT",
    headers: { "Content-Type": file.type },
    body: file,
  });

  return finalUrl;
}

الفوائد: خادمك لا يرى الملف أبداً — أسرع ومقاوم للتحميل الثقيل.

تحميل ملف

js
import { GetObjectCommand } from "@aws-sdk/client-s3";

const data = await s3.send(new GetObjectCommand({
  Bucket: BUCKET,
  Key: "path/to/file.jpg",
}));

const bytes = await data.Body.transformToByteArray();

للتحميل مباشرة من المتصفّح، أنشئ presigned GET URL بنفس الطريقة السابقة.

حذف

js
import { DeleteObjectCommand } from "@aws-sdk/client-s3";

await s3.send(new DeleteObjectCommand({
  Bucket: BUCKET,
  Key: "path/to/file.jpg",
}));

التحكّم بالصلاحيات

Bucket Policy للقراءة العامّة

إن كنت تخزّن صور موقع عامّة:

json
{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "PublicRead",
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::YOUR_BUCKET/public/*"
  }]
}

فقط المسار public/* سيكون عامّاً. البقية تتطلّب صلاحية.

CORS لرفع مباشر من المتصفّح

json
[
  {
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["PUT", "POST"],
    "AllowedOrigins": ["https://yoursite.com"],
    "ExposeHeaders": ["ETag"]
  }
]

تحسين التكاليف

S3 له عدّة طبقات سعرية:

| الطبقة | السعر/GB شهرياً | الاستخدام | |--------|-----------------|-----------| | Standard | $0.023 | ملفات نشطة | | Standard-IA | $0.0125 | وصول نادر | | Glacier | $0.004 | أرشيف طويل المدى | | Deep Archive | $0.00099 | نسخ قديمة جداً |

انقل الملفات القديمة تلقائياً بـ Lifecycle rules.

CloudFront: CDN عالمي

لتسريع الوصول عالمياً، أضف CloudFront أمام الـ bucket:

  1. CloudFront → Create distribution
  2. Origin: اختر الـ bucket
  3. Cache behavior: افتراضي مناسب للأغلبية
  4. احصل على domain مثل d123abc.cloudfront.net

الفوائد: سرعة أعلى 10x، تكاليف أقل، شهادة SSL مجانية.

بدائل أرخص

  • Cloudflare R2: مشابه S3 بسعر أرخص وبدون egress fees ($0.015/GB)
  • Backblaze B2: $0.005/GB — الأرخص
  • DigitalOcean Spaces: مشابه S3، واجهة أبسط

الكود تقريباً نفسه — فقط غيّر الـ endpoint.

أخطاء شائعة

"Access Denied"

  • تحقّق من IAM policy
  • تحقّق من bucket policy
  • انتبه لـ Block Public Access (قد يتجاوز الصلاحيات)

"SignatureDoesNotMatch"

  • صحّح الوقت على جهازك (NTP)
  • تحقّق من أنك تستخدم secret key صحيحاً

رفع بطيء

  • استخدم presigned URLs (رفع مباشر)
  • اختر Region قريباً من مستخدميك
  • استخدم Multipart Upload للملفات > 100MB

الأسئلة الشائعة

هل أحتاج AWS كاملاً؟

لا — يمكن استخدام S3 فقط بسهولة. الحساب المجاني يُعطيك 5GB شهرياً.

S3 vs serving من الخادم؟

S3 أفضل دائماً للملفات — أسرع، أرخص، لا يحمّل خادمك، CDN جاهز.

هل أستخدم S3 لقواعد البيانات؟

لا — S3 ليست قاعدة بيانات. للبيانات المنظّمة استخدم RDS/Postgres. S3 للملفات فقط.

اقرأ أيضاً

مقالات ذات صلة