اذهب إلى المحتوى

سنغطي في هذا المقال من سلسلة تعلم البرمجة:

مقدمة في برمجة خوادم الويب

في بدايات الإنترنت كنا نطلب صفحات HTML من خوادم الويب فتعطينا صفحات ثابتةً أو ساكنةً، ليس للمستخدمين أي يد في تعديل محتواها أو التفاعل معها، باستثناء بعض عمليات باتش batch processes التي استخدمتها بعض المواقع لإنشاء صفحات HTML من مصادر البيانات، لضمان تحديث معلومات تلك الصفحات، وفي هذه الحالة أيضًا لم يكن للمستخدمين دور في ما يظهر أمامهم على صفحة الويب.

ثم صرنا ندمج البرامج في خوادم الويب لتوليد الصفحات ديناميكيًا كلما طلبها المستخدم، وسميت الآلية المستخدمة في ذلك واجهة البوابة المشتركة Common Gateway Interface أو CGI اختصارًا، ولا يزال أثر تلك التقنية باقيًا في مواقع الويب التي نتصفحها حاليًا.

ومع استغلال المبرمجين إمكانيات واجهة CGI -مع وسم <form> في HTML- صارت المواقع التي يبنونها أكثر تطورًا وتعقيدًا، وصار من الممكن بناء مواقع التسوق الإلكتروني، والألعاب، والدعم الفني، وغيرها من الخدمات التي صارت اليوم بدهيات.

تُبنى واجهة CGI على مفهوم بسيط، هو أن بيانات الإدخال تُرسَل مثل جزء من رسالة http GET أو http POST، ويشير الرابط إلى مجلد خاص في خادم الويب، الذي يعرف أن عليه تنفيذ المورد resource بدلًا من إعادته، وهذا المورد هو برنامج يرسل الخرج الخاص به إلى مجرى الخرج القياسي stdout في صفحة HTML، فيقرأ الخادم مجرى الخرج القياسي، ويوجهه إلى العميل الذي طلب الصفحة.

سندرس الآن جزءًا من تلك المرحلة المبكرة في تطور خوادم الويب، بأن ننشئ خادم ويب بسيط على حاسوبنا المحلي، ليعطينا صفحة HTML ثابتةً، ثم نوسّع الصفحة لتشمل استمارةً تلتقط اسم المستخدم وترسله إلى الخادم، ونختم بإنشاء برنامج CGI يقرأ اسم المستخدم ذاك، ويعيد رسالة ترحيب مخصصةً باسمه من الخادم.

إنشاء صفحة ترحيب باستخدام واجهة CGI

توفر بايثون وحدة خادم ويب بسيطةً نستطيع استخدامها للاختبار والتطوير، قبل نقل الشيفرة إلى منصة استضافة ويب حقيقية في شبكة ما أو على الإنترنت، وسنبدأ بالنظر في كيفية تشغيلها لإرسال صفحات ويب ساكنة static web pages.

صفحة ويب بسيطة

أول ما علينا فعله هو إنشاء صفحة الويب التي نريد إرسالها، ولن نشرح كيفية كتابة شيفرة HTML بالتفصيل هنا، وإنما سنشرح ما يكفي لتشغيل الأمثلة التي نكتبها، وستبدو صفحة "Hello World" بسيطةً كما يلي:

<!doctype html>
<html>
   <head>
     <title>Hello world web page</title>
   </head>
   <body>
       <h1>Hello World</h1>
   </body>
</html>

تتكون HTML من وسوم، وهي أسماء محددة مسبقًا في توصيف اللغة نفسها، تحيط بها علامتا < و>، وتأتي أغلب الوسوم في أزواج يكون وسم الإغلاق فيها مسبوقًا بشرطة مائلة /، كما قد تحتوي الوسوم على بيانات تُعرف بالخاصيات attributes، غير أن المثال أعلاه ليس فيه أي منها لأننا بدأنا به بسيطًا، لكننا سنراها لاحقًا.

تجدر الإشارة هنا إلى أن بعض العناصر إجبارية في HTML، فيجب أن تحتوي كل صفحة HTML عليها على الأقل لتكون صالحةً، رغم أن أغلب المتصفحات الحالية ستعرض الصفحة حتى لو لم تكن هذه العناصر موجودةً، وتلك العناصر هي:

  1. التصريح doctype: يشير إلى أن هذا المستند هو مستند HTML، وقد كان هذا التصريح طويلًا ومفصلًا سابقًا، لكن -ومنذ صارت HTML5 قياسيةً ومعتمدةً- نكتفي بكتابة html في ذلك التصريح. لاحظ أن تنسيق الوسم في doctype مختلف عن وسوم HTML العادية، إذ توجد علامة تعجب مباشرةً بعد علامة ‎<‎.
  2. الوسم html: نستخدم زوجًا من الوسم <html> لتحديد بداية متن المستند نفسه ثم وسم إغلاق له، ويشكل هذا الوسم جذر المستند، وتمثَّل صفحات HTML في ذاكرة المتصفح في هيكل شجري، تكون قمته الوسم <html>. وتعدِّل شيفرة جافاسكربت التي في المتصفح ذلك الهيكل، لذا تؤثر طريقة كتابة HTML كثيرًا في كيفية كتابة شيفرة جافاسكربت، وكذلك في قراءة عملاء الويب web clients -مثل تلك التي كتبناها في المقال السابق- لتلك الصفحة.
  3. الوسم head: يحدد الوسم <head> جزءًا من الصفحة يحوي معلومات عن الصفحة نفسها، لكن المتصفح لا يعرضها، فمثلًا تعرَّف فيه بيانات أوراق الأنماط المتتالية أو التنسيقات الموروثة CSS، وقد يُستورد ملف CSS عند وجود عدة أنماط في الصفحة، كما تستورد ملفات جافاسكربت المستخدَمة في الصفحة. نلاحظ أننا أزحنا الوسوم في المثال أعلاه، لكن ذلك لا يؤثر على تنفيذ الشيفرة، وهو لتحسين قراءة الشيفرة وإظهار الهيكل الشجري المتشعب للمستند لا أكثر، ولا فرق بالنسبة للمتصفح سواء أزيحت الشيفرة أم لا، وقسم head غير إلزامي عند كتابة مستندات HTML نظريًا، لكن وجوده يرجع إلى حاجة أغلب المتصفحات الحديثة للمعلومات التي فيه.
  4. الوسم title: يحتوي هذا الوسم على عنوان الصفحة الذي سيعرضه المتصفح، وهو الجزء الوحيد المعروض من قسم الترويسة، رغم تأثير الأنماط وجافاسكربت في المظهر العام لمحتوى الصفحة الرئيسية.
  5. الوسم body: يغلف هذا الوسم المحتوى الأساسي للصفحة، والذي نراه في نافذة المتصفح.

هذه هي العناصر الأساسية لصفحة الويب، وقد استخدمنا الوسم <h1> الذي يحتوي رسالة "Hello World"، وهو جزء من مجموعة عناصر h -التي تشير إلى كلمة ترويسة header- وتُرقَّم من 1 إلى 6 لتوضح ترتيب عناوين الفقرات، ويصغر حجم الخط المستخدم ومظهره كلما اقتربنا من العنوان السادس، رغم إمكانية تعديل ذلك باستخدام CSS.

نحفظ شيفرة HTML في مستند باسم index.htm في مجلد باسم hello، ونتحقق من عمله بتحميله في متصفح ويب، فإذا عرض المتصفح الصفحة كما نريدها فنكون قد نجحنا في هذه المهمة البسيطة، وننتقل الآن إلى توفيره من خلال خادم الويب الخاص بنا.

تشغيل خادم الويب

يوجد خادم الويب الخاص ببايثون في وحدة http.server، ويمكن تشغيله دون أي تعديلات من خلال سطر أوامر نظام التشغيل، بتغيير المجلد العامل إلى مجلد hello الذي أنشأناه قبل قليل، كما يلي:

$ python -m http.server --cgi 8000

يحدد الخيار ‎-m في الشيفرة أعلاه الوحدة التي يجب أن تشغلها بايثون، أما الراية ‎--cgi فتفعّل عمليات واجهة CGI التي سنحتاج إليها لاحقًا، ويشير العدد 8000 إلى منفذ الشبكة الذي ستستخدمه.

تحميل صفحة الويب

نستطيع الآن الوصول إلى الخادم من خلال تحميل الرابط التالي في شريط عنوان المتصفح:

http://localhost:8000

إذا كان الخادم يعمل فستحمَّل تلك الصفحة وتُعرض كما فعلنا من قبل، إلا أنها الآن تُرسَل من قبل الخادم، كما يتضح من شريط العنوان في المتصفح، وبهذا نكون قد أرسلنا أول صفحة ويب لنا!

والسبب الذي يجعل هذه العملية ناجحةً دون تحديد اسم الملف هو أن خوادم الويب تبحث عن ملف باسم index.htm تلقائيًا، فإذا كان موجودًا ولم نحدّد ملفًا مسبقًا فسيُعرض index.htm. كما يمكن إعداد الخادم ليبحث عن ملفات افتراضية أخرى، مثل index.html أو index.php.

استخدام واجهة CGI لعرض رسالة ترحيب بالمستخدم

نريد الآن أن نوسع صفحة الويب السابقة لتلتقط اسم المستخدم وترسله إلى الخادم، الذي يرد بإرسال رسالة ترحيب مخصصة باسم المستخدم.

إنشاء استمارة HTML

الخطوة الأولى لذلك هي تعديل ملف HTML ليتضمن حقل إدخال لاسم المستخدم، كما يلي:

<!doctype html>
<html>
  <head>
    <title>Hello user page</title>
  </head>
  <body>
    <h1>Hello, welcome to our website!</h1>
    <form name="hello" 
          method="get" 
          action="http://localhost:8000/cgi-bin/sayhello.py">
      <p>Please tell us your name:</p>
      <input type="text" id="username" name="username" 
             size="30" required autofocus/>
      <input type="submit" value="Submit" />
    </form>
  </body>
</html>

نلاحظ هنا أن عناصر <form> تحتوي على خاصيات في وسومها، حيث تشكل الخاصية name جزءًا من البيانات المرسَلة إلى الخادم مع القيمة التي في صندوق الإدخال النصي، وتخبر الخاصية method الخاصة بوسم form المتصفح نوع رسالة http التي يجب إرسالها -وهي GET في هذه الحالة-، كما تخبره الخاصية action بالمكان الذي يجب أن يرسلها إليه.

تخبر خاصيتا العنصر input الأخيرتان المتصفح ألا يرسل الاستمارة إلا إذا احتوى الحقل النصي على قيمة، وأن يضع المؤشر في ذلك الحقل ليكون مستعدًا لاستقبال الإدخال، كما تخبر القيمة submit الموجودة في نوع الإدخال type المتصفح أن يعرض هذا العنصر مثل زر تظهر عليه الكلمة الموجودة في قيمة الخاصية value -والتي هي submit أيضًا-، وسيرسل ذلك الزر الاستمارة عند الضغط عليه إلى الخاصية action الخاصة بالاستمارة.

نحفظ هذا في نفس المجلد كما فعلنا من قبل، لكن نستدعي hello.htm في هذه المرة، ونتحقق من صحة عملها بكتابة ما يلي في شريط العنوان:

http://localhost:8000/hello.htm

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

كتابة شيفرة CGI

يشبه برنامج CGI برامج بايثون التي كتبناها من قبل، باستثناء أمرين هما:

  • برنامج CGI يستورد وحدة CGI.
  • يوجد في مجلد باسم cgi-bin، في جذر خادم الويب، ويكون هذا البرنامج تنفيذيًا executable، لنحقق الأمر الثاني ننشئ مجلد cgi-bin داخل مجلد html، ثم ننشئ ملفًا داخل ذلك المجلد الجديد ونسميه sayhello.py يحتوي على الشيفرة التالية:
#!/usr/bin/env python3
import cgi

# استخرج حقول البيانات
data = cgi.FieldStorage()
username = data["username"].value 

# \n\n الإجبارية مع اللاحقة http أرسل ترويسة:
print("ContentType: text/html\n\n") 

# HTML والآن، أرسل محتوى
print("<!doctype html>\n<html><head>")
print("<title>Hello %s</title></head>" % username)
print('''
<body>
   <h1>Welcome %s</h1>
</body>
</html>''' % username)

تنفَّذ العمليات الخاصة بالبيانات داخل استدعاء FieldStorage، حيث تجمع وحدة cgi جميع البيانات من طلب http، وتضعها في قاموس لنستطيع الوصول إليها بسهولة باستخدام مفاتيح نصية هي خاصيات name من الاستمارة الخاصة بنا.

نلاحظ كيف تمكننا علامات الاقتباس الثلاثية الخاصة ببايثون من هيكلة الخرج في HTML بصورة يمكن قراءتها -انظر قسم head و body.

بعد أن نحفظ الصفحة، نتأكد من تغيير الصلاحيات ليكون الملف قابلًا للتنفيذ من جميع المستخدمين، فإذا أعدنا تحميل صفحة hello.htm، وملأنا الاستمارة فسنحصل على رسالة ترحيب من الخادم عند الضغط على الزر.

تصلح هذه التقنية لمثل هذه التطبيقات البسيطة، وتمتاز بشفافية الخطوات، ومن ثم سهولة تصحيحها، غير أنه مع زيادة حجم المواقع وتعقيد البيانات لا تكون واجهة CGI مناسبةً للعمل معها، وهنا يأتي دور أطر عمل الويب frameworks، والتي سننظر فيها في المقال التالي.

خاتمة

نأمل في نهاية هذا المقال أن تكون تعلمت ما يلي:

  • تُنشأ الطلبات إلى خوادم الويب باستخدام طلبات http GET.
  • يرد خادم الويب بمستند HTML.
  • تُمرَّر البيانات في رابط الطلب أو متغيرات البيئة.
  • تعالج وحدة CGI البروتوكول الأساسي.
  • تُجلب بيانات الاستمارة من خلال قاموس FieldStorage.
  • واجهة CGI مناسبة لاستمارات الويب البسيطة، مثل شاشات تسجيل الدخول، إلا أنها لا تناسب التطبيقات الكبيرة.

ترجمة -بتصرف- للفصل الثلاثين: Writing Web Applications من كتاب Learn To Program لصاحبه Alan Gauld.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...