12. خدمات وب در پایتون
![]() |
اسکریپتهای پایتون میتوانند توسط یک سرور WEB اجرا شوند. این سرور است که به درخواستهای کلاینت گوش میدهد. از دیدگاه کلاینت، فراخوانی یک سرویس WEB معادل درخواست URL آن سرویس است. کلاینت میتواند به هر زبانی، از جمله پایتون، نوشته شود. ما باید بتوانیم با یک سرویس WEB «ارتباط» برقرار کنیم، یعنی پروتکل ارتباطی Http بین یک وبسرور و کلاینتهای آن را درک کنیم. این هدف برنامههای بعدی است.
اسکریپتهای سرویس وب توسط وبسرور آپاچی برای WampServer اجرا خواهند شد. آنها باید در یک دایرکتوری خاص قرار گیرند: <WampServer>\bin\apache\apachex.y.z\cgi-bin، که در آن <WampServer> مسیر نصب WampServer و x.y.z نسخه وبسرور آپاچی است.
![]() |
فقط قرار دادن اسکریپتهای پایتون در پوشه <cgi-bin> کافی نیست. اسکریپت باید در خط اول مسیر تفسیرگر پایتون مورد استفاده را مشخص کند. این مسیر بهعنوان یک نظر (comment) درج میشود:
خوانندگان باید این مسیر را متناسب با محیط خود تطبیق دهند.
12.1. برنامه تاریخ و زمان مشتری/سرور
اولین سرویس وب ما یک سرویس تاریخ و زمان خواهد بود: کلاینت تاریخ و زمان فعلی را دریافت میکند.
12.1.1. سرور
#!D:\Programs\ActivePython\Python2.7.2\python.exe
import time
# سربرگها
print "Content-Type: text/plain\n"
#زمان ارسال به کلاینت
# localtime: تعداد میلیثانیهها از ۱ ژانویه ۱۹۷۰
# "قالب نمایش تاریخ و زمان
# d: روز (۲ رقم)
# m: ماه دو رقمی
# y: سال (۲ رقم)
# H: ساعت 0.23
# M: دقیقه
# S: ثانیهها
print time.strftime('%d/%m/%y %H:%M:%S',time.localtime())
یادداشتها:
- خط ۶: اسکریپت باید خود برخی از سربرگهای HTTP را در پاسخ به کلاینت تولید کند. این سربرگها به سربرگهای HTTP تولید شده توسط خود سرور آپاچی اضافه میشوند. سربرگ HTTP در خط ۶ به کلاینت میگوید که یک منبع با فرمت text/plain در حال ارسال است، یعنی متن بدون قالببندی. به «\n» در انتهای هدر توجه کنید که یک خط خالی پس از هدر ایجاد میکند. این امر الزامی است: این خط خالی به کلاینت HTTP سیگنال پایان هدرهای HTTP در پاسخ را میدهد. در ادامه، منبعی که توسط کلاینت درخواست شده است میآید، که در این مورد متن بدون قالببندی است؛
- خط ۱۸: منبعی که برای کلاینت ارسال میشود، متنی است که تاریخ و زمان فعلی را نمایش میدهد.
12.1.2. دو تست
اسکریپت بالا را میتوان مستقیماً توسط تفسیرگر پایتون در یک پنجرهٔ فرمان اجرا کرد، همانطور که تا اینجا انجام دادهایم. این کار به حذف هرگونه خطای نحوی یا خطای زمان اجرا کمک میکند. نتیجهٔ زیر به دست میآید:
پس از آنکه اسکریپت به این روش آزمایش شد، میتوان آن را در پوشه <cgi-bin> روی سرور آپاچی قرار داد (به پاراگراف ۱۲ مراجعه کنید). بیایید برنامه WampServer را اجرا کنیم. این کار هم یک سرور وب آپاچی و هم یک سیستم مدیریت پایگاه داده MySQL را راهاندازی میکند. فعلاً، ما فقط از وبسرور استفاده خواهیم کرد. سپس، با استفاده از یک مرورگر وب، بیایید URL زیر را درخواست کنیم: http://localhost/cgi-bin/web_02.py:
![]() |
- به [1]: URL درخواستی؛
- به [2]: پاسخی که توسط مرورگر نمایش داده میشود؛
- در [3]: کد منبع دریافتشده توسط مرورگر وب. این دقیقاً همان چیزی است که توسط اسکریپت پایتون ارسال شده است.
با استفاده از ابزارهای خاصی (در این مورد Firebug، افزونهٔ مرورگر Firefox)، میتوانید سربرگهای HTTP مبادله شده با سرور را مشاهده کنید. در بالا، مرورگر وب سربرگهای HTTP زیر را دریافت کرد:
خطوط ۷–۸ هدر HTTP ارسالشده توسط اسکریپت پایتون را نشان میدهند. هدرهای قبلی توسط وبسرور آپاچی تولید شدهاند.
12.1.3. یک کلاینت برنامهریزیشده
اکنون یک اسکریپت مینویسیم که بهعنوان کلاینت برای سرویس وب قبلی عمل خواهد کرد. از امکانات ماژول httplib استفاده خواهیم کرد که نوشتن کلاینتهای HTTP را آسانتر میکند.
# -*- coding=utf-8 -*-
import httplib,re
# ثوابت
HOST="localhost"
URL="/cgi-bin/web_02.py"
# اتصال
connexion=httplib.HTTPConnection(HOST)
# ردیابی
connexion.set_debuglevel(1)
#ارسال درخواست
connexion.request("GET", URL)
#پردازش پاسخ
reponse=connexion.getresponse()
# محتوا
contenu=reponse.read()
# خروج
connexion.close()
print "------\n",contenu,"-----\n"
#بازیابی دادههای مرتبط با زمان
elements=re.match(r"^(\d\d)/(\d\d)/(\d\d) (\d\d):(\d\d):(\d\d)\s*$",contenu).groups()
print "Jour=%s,Mois=%s,An=%s,Heures=%s,Minutes=%s,Secondes=%s" % (elements[0],elements[1],elements[2],elements[3],elements[4],elements[5])
یادداشتها:
- خط ۳: ماژول re برای عبارات باقاعده و ماژول httplib برای توابع کلاینت HTTP مورد نیاز است؛
- خط ۹: یک اتصال HTTP با استفاده از پورت ۸۰ ماژول HOST، همانطور که در خط ۶ تعریف شده، برقرار میشود؛
- خط ۱۱: لاگ به شما امکان میدهد تا سربرگهای HTTP درخواست کلاینت و پاسخ سرور را مشاهده کنید؛
- خط ۱۳: سرویس وب URL فراخوانی میشود. دو روش برای درخواست آن وجود دارد: استفاده از فرمان HTTP GET یا POST. تفاوت بین این دو در ادامه توضیح داده شده است. در اینجا، با استفاده از فرمان HTTP GET درخواست خواهد شد؛
- خط ۱۵: پاسخ سرور خوانده میشود. در اینجا کل پاسخ دریافت میشود: هدرهای HTTP و منبعی که توسط کلاینت درخواست شده است. در پاسخ خود، سرور ممکن است به کلاینت دستور داده باشد که هدایت (redirect) کند. در این صورت، کلاینت httplib به طور خودکار هدایت را انجام میدهد. بنابراین، پاسخ دریافتشده همان چیزی است که در نتیجه هدایت به دست میآید؛
- خط ۱۷: پاسخ شامل سربرگهای HTTP و سند درخواستی کلاینت است. برای بازیابی فقط سربرگهای HTTP، از [reponse].getHeaders() استفاده میکنیم. برای بازیابی سند، از [reponse].read() استفاده میکنیم؛
- خط ۱۹: پس از دریافت پاسخ از سرور وب، اتصال به آن بسته میشود؛
- ما میدانیم که سند ارسالشده توسط سرور یک خط متن در قالب 15/06/11 14:56:36 است. خطوط 22–26: از یک عبارت منظم برای استخراج عناصر مختلف از این خط استفاده میشود.
12.1.4. نتایج
یادداشتها:
- خط ۱: سربرگهای HTTP ارسالشده توسط کلاینت به وبسرور؛
- خطوط ۲–۶: سربرگهای HTTP در پاسخ وبسرور؛
- خط ۸: سندی که توسط سرور ارسال شده است؛
- خط ۱۱: نتیجهٔ پردازش آن؛
12.2. سرور در حال بازیابی پارامترهای ارسالشده توسط کلاینت
در پروتکل HTTP، کلاینت دو روش برای ارسال پارامترها به سرور وب دارد:
- در پروتکل HTTP، کلاینت دو روش برای ارسال پارامترها به وبسرور دارد:
GET url?param1=val1¶m2=val2¶m3=val3… HTTP/1.0
که در آن مقادیر vali ابتدا باید کدگذاری شوند تا برخی کاراکترهای رزرو شده با مقادیر هگزادسیمال خود جایگزین شوند.
- این سرویس را به شکل URL درخواست میکند
سپس، در میان سربرگهای HTTP ارسالشده به سرور، سربرگ زیر گنجانده میشود:
بقیهٔ سرآیندهای ارسالشده توسط کلاینت با یک خط خالی پایان مییابند. سپس کلاینت میتواند دادههای خود را به صورت ارسال کند
که در آن 'vali' باید، مانند روش 'GET'، از قبل رمزگذاری شود. تعداد کاراکترهای ارسالشده به سرور باید N باشد، که N مقدار اعلامشده در هدر است:
12.2.1. سرویس وب
سرویس وب زیر سه پارامتر را از کلاینت خود دریافت میکند: nom، prenom، age. این پارامترها را از نوعی فرهنگ لغت به نام cgi.FieldStorage که توسط ماژول cgi فراهم شده است، بازیابی میکند. مقدار vali یک پارامتر parami از طریق vali=cgi.FieldStorage().getlist("parami") به دست میآید. این تابع آرایهای از موارد زیر را برمیگرداند:
- 0 عنصر اگر پارامتر parami در درخواست کلاینت وجود نداشته باشد؛
- ۱ عنصر اگر پارامتر parami یک بار در درخواست کلاینت ظاهر شود؛
- n عنصر اگر پارامتر parami به تعداد n در درخواست کلاینت ظاهر شود.
پس از بازیابی پارامترها، اسکریپت آنها را به کلاینت بازمیگرداند.
#!D:\Programs\ActivePython\Python2.7.2\python.exe
import cgi
# سربرگها
print "Content-Type: text/plain\n"
#بازیابی اطلاعات ارسالشده توسط کلاینت توسط سرور
# در اینجا: first_name=P&surname=N&age=A
formulaire=cgi.FieldStorage()
# اینها به کلاینت بازگردانده میشوند
print "informations recues du service web [prenom=%s,nom=%s,age=%s]" % (formulaire.getlist("prenom"),formulaire.getlist("nom"),formulaire.getlist("age"))
میتوان یک تست را با استفاده از یک مرورگر وب انجام داد:
![]() |
در [1]، پاسخ URL از سرویس وب. توجه داشته باشید که سه پارامتر nom، prenom و age وجود دارند. در [2]، پاسخ سرویس وب.
12.2.2. کلاینت GET
# -*- coding=utf-8 -*-
import httplib,urllib
# ثوابت
HOST="localhost"
URL="/cgi-bin/web_03.py"
PRENOM="Jean-Paul"
NOM="de la Huche"
AGE=42
#پارامترها باید قبل از ارسال به سرور رمزگذاری شوند
params = urllib.urlencode({'nom': NOM, 'prenom': PRENOM, 'age': AGE})
#پارامترها در انتهای URL قرار میگیرند
URL+="?"+params
#اتصال
connexion=httplib.HTTPConnection(HOST)
# ردیابی
connexion.set_debuglevel(1)
#ارسال درخواست
connexion.request("GET",URL)
#پردازش پاسخ
reponse=connexion.getresponse()
# محتوا
contenu=reponse.read()
print contenu,"\n"
# اتصال بسته شد
connexion.close()
یادداشتها:
- خطوط ۸–۱۰: مقادیر سه پارامتر ارسالشده به سرویس وب؛
- خط ۱۳: اینها باید رمزگذاری شوند. این کار با استفاده از متد urlencode ماژول urllib انجام میشود. این ماژول در خط ۳ وارد شده است. این متد یک دیکشنری {param1:val1, param2:val2, ...} را به عنوان پارامتر میپذیرد؛
- خط 15: در یک فرمان GET (خط 21)، کلاینت باید پارامترهای رمزگذاریشده را در انتهای URL سرویس وب قرار دهد؛
- خطوط زیر قبلاً مورد بحث قرار گرفتهاند.
12.2.3. نتایج
یادداشتها:
- خط ۲: به رمزگذاری پارامترها (نام خانوادگی، نام، سن) توجه کنید؛
- خط ۸: پاسخ سرویس وب.
12.2.4. کلاینت POST
کلاینت POST مشابه کلاینت GET است، با این تفاوت که پارامترهای رمزگذاریشده دیگر بخشی از هدف URL نیستند. آنها بهعنوان سومین آرگومان درخواست POST (خط ۱۹) ارسال میشوند.
# -*- coding=utf-8 -*-
import httplib,urllib
# ثوابت
HOST="localhost"
URL="/cgi-bin/web_03.py"
PRENOM="Jean-Paul"
NOM="de la Huche"
AGE=42
#پارامترها باید قبل از ارسال به سرور رمزگذاری شوند
params = urllib.urlencode({'nom': NOM, 'prenom': PRENOM, 'age': AGE})
#اتصال
connexion=httplib.HTTPConnection(HOST)
# ردیابی
connexion.set_debuglevel(1)
#ارسال درخواست
connexion.request("POST",URL,params)
#پردازش پاسخ
reponse=connexion.getresponse()
#محتوا
contenu=reponse.read()
print contenu,"\n"
# اتصال بسته شد
connexion.close()
12.2.5. نتایج
یادداشتها:
- توجه خط ۲: متدی که توسط کلاینت POST برای ارسال پارامترهای رمزگذاریشده استفاده میشود:
- سربرگ HTTP Content-Length تعداد کاراکترهایی را که باید به سرویس وب ارسال شود مشخص میکند؛
- سپس یک خط خالی که پایان هدرهای HTTP را نشان میدهد، به دنبال این هدر HTTP میآید؛
- سپس ۳۹ کاراکتر پارامترهای رمزگذاریشده ارسال میشوند.
- خط ۸: پاسخ سرویس وب.
12.3. بازیابی متغیرهای محیطی از یک سرویس وب
12.3.1. سرویس وب
اسکریپت CGI پایتون در یک محیط سیستمی اجرا میشود که دارای ویژگیها است. ویژگیها و مقادیر آنها در یک دیکشنری به نام os.environ در دسترس هستند.
#!D:\Programs\ActivePython\Python2.7.2\python.exe
import os
# سربرگها
print "Content-Type: text/plain\n"
# اطلاعات محیط
for (cle,valeur) in os.environ.items():
print "%s : %s" % (cle,valeur)
نکات:
- خط ۳: برای دسترسی به متغیرهای «system» باید ماژول os را وارد کنید.
اگر اسکریپت بالا را مستقیماً اجرا کنید (c.a.d بهعنوان یک اسکریپت کنسول بهجای یک اسکریپت CGI)، نتایج زیر در کنسول ظاهر میشوند:
در یک مرورگر وب (جایی که اسکریپت CGI اجرا میشود)، نتایج زیر نمایش داده میشوند:
![]() |
توجه داشته باشید که بسته به زمینه اجرای برنامه، محیط بهدستآمده یکسان نخواهد بود.
12.3.2. کلاینت برنامهریزیشده
# -*- coding=utf-8 -*-
import httplib
# ثوابت
HOST="localhost"
URL="/cgi-bin/web_04.py"
# اتصال
connexion=httplib.HTTPConnection(HOST)
#ارسال درخواست
connexion.request("GET", URL)
#پردازش پاسخ
reponse=connexion.getresponse()
# محتوا
print reponse.read()
12.3.3. نتایج
باید توجه داشت که کلاینت برنامهریزیشده دقیقاً همان پاسخی را که مرورگر وب دریافت میکند، دریافت نمیکند. این به این دلیل است که مرورگر وب اطلاعاتی را به سرور وب ارسال کرد که سرور وب از آن برای تولید پاسخ خود استفاده کرد. در این مورد، کلاینت برنامهریزیشده هیچ اطلاعاتی در مورد خود ارسال نکرد.




