الخطوة 6 في الواجهة الخلفية: CORS
مكّن تطبيق الجوال من الاتصال بالواجهة الخلفية عبر إعداد CORS.
ما ستتعلمه
- ما هو CORS ولماذا وُجد
- كيف تمكّن CORS في Flask
- تقييد CORS لأغراض الأمان
الخطوة 1: ما هو CORS؟
CORS (Cross-Origin Resource Sharing) ميزة أمان في المتصفح. وهي تمنع صفحة ويب من أصل (origin) معين (مثل http://localhost:8081) من إرسال طلبات إلى أصل مختلف (مثل http://localhost:5000).
في هذا المشروع:
- يعمل تطبيق React Native على http://localhost:8081 (خادم تطوير Expo)
- تعمل واجهتك الخلفية في Flask على http://localhost:5000
- هذان أصلان مختلفان (منفذان مختلفان)، لذلك يحجب المتصفح الطلب
ملاحظة عن React Native: على جهاز حقيقي، لا ينطبق CORS بالطريقة نفسها. لكن خادم تطوير Expo يعمل في بيئة قائمة على المتصفح، وفيها يكون CORS مهمًا.
الخطوة 2: تثبيت flask-cors
إذا كنت قد ثبّتته بالفعل في الخطوة 1 فأنت جاهز. وإن لم تفعل:
pip install flask-cors
الخطوة 3: تحديث init.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
from dotenv import load_dotenv
load_dotenv()
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///chat.db"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
CORS(app)
db.init_app(app)
from .routes import api
app.register_blueprint(api, url_prefix="/api")
with app.app_context():
db.create_all()
return app
if __name__ == "__main__":
app = create_app()
app.run(debug=True, port=5000)
السطر الواحد CORS(app) يمكّن CORS لكل الأصول، ولكل الطرق، ولكل الترويسات.
الخطوة 4: تقييد CORS (اختياري لكنه مُستحسن)
بدلًا من السماح بأي أصل، اقتصر على تطبيق جوالك:
CORS(app, origins=["http://localhost:8081", "http://localhost:19006", "exp://192.168.1.100:19000"])
الخطوة 5: اختبار CORS
cd aiproject/backend
source venv/bin/activate
python app/__init__.py
افحص الترويسات:
curl -I http://127.0.0.1:5000/api/status
ابحث عن هذه الترويسة في الاستجابة:
Access-Control-Allow-Origin: *
كيف يعمل CORS
- يرسل تطبيق جوالك طلبًا إلى الواجهة الخلفية
- يتحقق المتصفح (أو Expo) مما إذا كانت الاستجابة تحمل ترويسة
Access-Control-Allow-Origin - إذا طابقت الترويسة أصل التطبيق، يُسمح بالطلب
- وإذا لم تطابق، يحجب المتصفح الطلب
يضيف CORS(app) هذه الترويسة تلقائيًا إلى كل استجابة.
الخطوة 6: إضافة المراقبة
يحتاج تطبيق الإنتاج إلى قابلية المراقبة — أي أنك تحتاج إلى معرفة ما يجري. أضف نقطة نهاية لفحص الصحة تتحقق من قاعدة البيانات وتتابع المقاييس.
نقطة نهاية فحص الصحة
أضف إلى backend/app/__init__.py:
@app.route("/api/health")
def health():
db_ok = False
try:
with app.app_context():
db.session.execute(db.text("SELECT 1"))
db_ok = True
except Exception:
db_ok = False
return jsonify({
"status": "ok",
"version": "1.0.0",
"database": "connected" if db_ok else "disconnected",
"metrics": get_metrics(),
})
اختبرها:
curl http://127.0.0.1:5000/api/health
# → {"status":"ok","version":"1.0.0","database":"connected","metrics":{...}}
نقطة نهاية المقاييس
تتابع نقطة النهاية /api/metrics عدد الطلبات. أضف إلى backend/app/metrics.py:
_request_count = 0
def track_request(response):
global _request_count
_request_count += 1
return response
def register_metrics(app):
app.after_request(track_request)
@app.route("/api/metrics")
def metrics():
return jsonify({"total_requests": _request_count})
الآن كل طلب يزيد العداد. زر /api/metrics لترى عدد الطلبات التي عالجها خادمك.
تسجيل منظّم
بدلًا من عبارات print()، استخدم تسجيلًا منظّمًا. أضف إلى backend/app/logging_config.py:
import logging
import sys
def setup_logging():
logger = logging.getLogger("aiproject")
logger.setLevel(logging.INFO)
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(logging.Formatter(
"%(asctime)s [%(levelname)s] %(message)s"
))
logger.addHandler(handler)
return logger
ثم في routes.py:
logger = logging.getLogger("aiproject")
logger.info("Chat completed: user_msg=%s ai_msg=%s", user_msg.id, ai_msg.id)
تظهر السجلات مع طوابع زمنية:
2026-05-04 14:30:22 [INFO] Chat completed: user_msg=5 ai_msg=6
الخطوة 7: إعداد خطافات pre-commit
تشغّل خطافات pre-commit فحوصًا تلقائيًا قبل كل git commit. وإذا فشل أحد الفحوص، يُحجب الـ commit، وهذا يمنع دخول كود سيئ إلى مستودعك.
ثبّت pre-commit:
pip install pre-commit
ثبّت الخطافات في مستودعك:
cd aiproject
pre-commit install
الآن في كل مرة تشغّل فيها git commit، ينفّذ pre-commit ما يلي:
1. ruff — فحص الكود
2. ruff-format — تنسيق الكود تلقائيًا
3. التحقق من المسافات الزائدة في نهاية الأسطر
4. التحقق من الأسطر الجديدة الناقصة في نهاية الملفات
جرّبه:
git add .
git commit -m "Test pre-commit hooks"
إذا وجد ruff مشكلة، يُحجب الـ commit. أصلح المشكلة وحاول مرة أخرى.
التحقق
- الواجهة الخلفية تعمل
- يُظهر
curl -IالترويسةAccess-Control-Allow-Origin: * - يُظهر
curl /api/healthأن قاعدة البيانات متصلة - تعمل خطافات pre-commit قبل كل commit
- يستطيع تطبيق جوالك الآن الاتصال بالواجهة الخلفية (سنختبر ذلك في قسم الجوال)