xmlrpc.client --- دسترسی کلاینت XML-RPC¶
کد منبع: Lib/xmlrpc/client.py
XML-RPC یک روش فراخوانی رویهای دوردست (Remote Procedure Call) است که از XML منتقلشده از طریق HTTP(S) بهعنوان یک انتقال استفاده میکند. با استفاده از آن، یک کلاینت میتواند متدهایی با پارامترها را روی یک سرور دوردست فراخوانی کند (سرور با یک URI نامگذاری میشود) و دادههای ساختاریافته را دریافت کند. این ماژول از نوشتن کد کلاینت XML-RPC پشتیبانی میکند؛ این ماژول تمام جزئیات تبدیل بین اشیای پایتون قابلتطبیق و XML در شبکه را مدیریت میکند.
هشدار
ماژول xmlrpc.client در برابر دادههایی که بدخواهانه ساخته شدهاند امن نیست. اگر نیاز دارید دادههای غیرقابلاعتماد یا احراز هویتنشده را تجزیه کنید، امنیت XML را ببینید.
تغییر یافته در نسخهی 3.5: برای URIهای HTTPS، xmlrpc.client اکنون بهطور پیشفرض تمام بررسیهای لازم مربوط به گواهی و نام میزبان را انجام میدهد.
دسترسپذیری: not WASI.
این ماژول در WebAssembly کار نمیکند یا در دسترس نیست. برای اطلاعات بیشتر، سکوهای WebAssembly را ببینید.
- class xmlrpc.client.ServerProxy(uri, transport=None, encoding=None, verbose=False, allow_none=False, use_datetime=False, use_builtin_types=False, *, headers=(), context=None)¶
نمونهای از
ServerProxyشیءای است که ارتباط با یک سرور XML-RPC دوردست را مدیریت میکند. اولین آرگومان ضروری یک URI (Uniform Resource Indicator) است و معمولاً URL سرور خواهد بود. دومین آرگومان اختیاری نمونهای از کارخانهی انتقال (transport factory) است؛ بهطور پیشفرض، برای URLهای https: نمونهای درونی ازSafeTransportو در غیر این صورت نمونهای درونی ازTransportبرای HTTP است. سومین آرگومان اختیاری یک کدگذاری است که بهطور پیشفرض UTF-8 است. چهارمین آرگومان اختیاری یک پرچم اشکالزدایی است.پارامترهای زیر نحوهی استفاده از نمونهی پراکسی برگرداندهشده را کنترل میکنند. اگر allow_none برابر true باشد، ثابت
Noneپایتون به XML تبدیل خواهد شد؛ رفتار پیشفرض این است کهNoneباعث پرتابTypeErrorشود. این یک افزونهی رایج برای مشخصات XML-RPC است، اما همهی کلاینتها و سرورها از آن پشتیبانی نمیکنند؛ برای توضیحات به http://ontosys.com/xml-rpc/extensions.php مراجعه کنید. میتوان از پرچم use_builtin_types استفاده کرد تا مقادیر تاریخ/زمان بهصورت اشیایdatetime.datetimeارائه شوند و دادهی دودویی بهصورت اشیایbytesارائه شود؛ این پرچم بهطور پیشفرض false است. میتوان اشیایdatetime.datetime،bytesوbytearrayرا به فراخوانیها ارسال کرد. پارامتر headers یک دنبالهی اختیاری از سرآیندهای HTTP برای ارسال با هر درخواست است که بهصورت دنبالهای از تاپلهای دوتایی بیان میشود و نشاندهندهی نام سرآیند و مقدار آن است. (برای مثال[('Header-Name', 'value')]). اگر URL HTTPS ارائه شود، context میتواندssl.SSLContextباشد و تنظیمات SSL اتصال HTTPS زیربنایی را پیکربندی کند. پرچم منسوخشدهی use_datetime مشابه use_builtin_types است، اما فقط برای مقادیر تاریخ/زمان اعمال میشود.تغییر یافته در نسخهی 3.3: پرچم use_builtin_types افزوده شد.
تغییر یافته در نسخهی 3.8: پارامتر headers افزوده شد.
هر دو انتقال HTTP و HTTPS از افزونهی سینتکس URL برای احراز هویت پایهی HTTP پشتیبانی میکنند:
http://user:pass@host:port/path. بخشuser:passبهصورت base64 کدگذاری میشود و در قالب سرآیند 'Authorization' HTTP، بهعنوان بخشی از فرایند اتصال هنگام فراخوانی یک متد XML-RPC به سرور راهدور ارسال میشود. تنها در صورتی نیاز است از این استفاده کنید که سرور راهدور به کاربر و گذرواژه برای احراز هویت پایه نیاز داشته باشد.نمونهی برگرداندهشده یک شیء پراکسی با متدهایی است که میتوان از آنها برای انجام فراخوانیهای RPC متناظر روی سرور راهدور استفاده کرد. اگر سرور راهدور از API دروننگری پشتیبانی کند، همچنین میتوان از پراکسی برای پرسوجو از سرور راهدور دربارهی متدهایی که پشتیبانی میکند (کشف سرویس) و واکشی سایر فرادادههای مرتبط با سرور استفاده کرد.
انواع سازگار (برای نمونه، آنهایی که میتوانند از طریق XML مارشال (marshalled) شوند)، شامل موارد زیر هستند (و مگر در مواردی که ذکرشده باشد، بهصورت همان نوع پایتون از حالت مارشال خارج (unmarshalled) میشوند):
نوع XML-RPC
نوع پایتون
booleanint،i1،i2،i4،i8یاbigintegerintدر بازهی -۲۱۴۷۴۸۳۶۴۸ تا ۲۱۴۷۴۸۳۶۴۷. مقادیر برچسب<int>را دریافت میکنند.doubleیاfloatfloat. مقادیر برچسب<double>را دریافت میکنند.stringarraylistیاtupleشامل عناصر سازگار. آرایهها بهصورتlistsبرگردانده میشوند.structdict. کلیدها باید از جنس رشته باشند، مقادیر میتوانند از هر نوع سازگار (conformable) باشند. میتوان اشیایی از کلاسهای تعریفشده توسط کاربر را نیز ارسال کرد؛ تنها ویژگی__dict__آنها منتقل میشود.dateTime.iso8601DateTimeیاdatetime.datetime. نوع برگرداندهشده به مقادیر پرچمهای use_builtin_types و use_datetime بستگی دارد.base64Binary،bytesیاbytearray. نوع بازگشتی به مقدار پرچم use_builtin_types بستگی دارد.nilثابت
None. ارسال آن فقط در صورتی مجاز است که allow_none درست باشد.bigdecimaldecimal.Decimal. فقط نوع بازگشتی.این مجموعهی کاملی از انواع داده است که توسط XML-RPC پشتیبانی میشود. فراخوانیهای متد همچنین ممکن است یک نمونهی خاص از
Faultرا پرتاب کنند که برای نشان دادن خطاهای سرور XML-RPC استفاده میشود، یاProtocolErrorکه برای نشان دادن خطایی در لایهی انتقال HTTP/HTTPS استفاده میشود. هر دوFaultوProtocolErrorاز یک کلاس پایه به نامErrorمشتق شدهاند. توجه داشته باشید که ماژول کلاینتی xmlrpc در حال حاضر نمونههای زیرکلاسهای انواع توکار را مارشال (marshal) نمیکند.هنگام ارسال رشتهها، نویسههای ویژهی XML مانند
<،>و&بهطور خودکار خنثی میشوند. با این حال، بر عهدهی فراخواننده است که اطمینان حاصل کند رشته عاری از نویسههایی است که در XML مجاز نیستند، مانند نویسههای کنترلی با مقادیر ASCII بین ۰ تا ۳۱ (البته بهجز تب، خط جدید و بازگشت به ابتدای سطر)؛ عدم انجام این کار باعث میشود درخواست XML-RPC حاصل، XML خوشساخت نباشد. اگر نیاز به ارسال بایتهای دلخواه از طریق XML-RPC دارید، از کلاسهایbytesیاbytearrayیا کلاس پوششیBinaryکه در ادامه توضیح داده شده است استفاده کنید.Serverبرای سازگاری با نسخههای قبلی، بهعنوان نام مستعاری برایServerProxyنگه داشته شده است. کدهای جدید باید ازServerProxyاستفاده کنند.تغییر یافته در نسخهی 3.5: آرگومان context اضافه شد.
تغییر یافته در نسخهی 3.6: پشتیبانی از برچسبهای نوع دارای پیشوند (برای مثال
ex:nil) افزوده شد. پشتیبانی از بازگشایی (unmarshalling) انواع اضافی که پیادهسازی Apache XML-RPC برای مقادیر عددی استفاده میکند، افزوده شد:i1،i2،i8،biginteger،floatوbigdecimal. برای توضیحات، https://ws.apache.org/xmlrpc/types.html را ببینید.
همچنین ملاحظه نمائید
- راهنمای عملی XML-RPC
توضیحی خوب دربارهی عملکرد XML-RPC و نرمافزارهای کلاینت به چند زبان. تقریباً شامل همهی چیزهایی است که یک توسعهدهندهی کلاینت XML-RPC باید بداند.
- دروننگری XML-RPC
افزونهی پروتکل XML-RPC برای دروننگری را توصیف میکند.
- مشخصات XML-RPC
مشخصات رسمی.
اشیای ServerProxy¶
یک نمونه ServerProxy دارای یک متد متناظر با هر فراخوانی رویهی راه دور پذیرفتهشده توسط سرور XML-RPC است. فراخوانی این متد یک RPC انجام میدهد که بر اساس هر دو نام و امضای آرگومان اعزام (dispatch) میشود (برای مثال، همان نام متد میتواند با چندین امضای آرگومان سربارگذاری (overload) شود). این RPC با برگرداندن یک مقدار پایان مییابد، که ممکن است دادهی برگرداندهشده در یک نوع منطبق باشد یا یک شیء Fault یا ProtocolError که نشاندهندهی یک خطا است.
سرورهایی که از API دروننگری XML پشتیبانی میکنند، از برخی متدهای رایج پشتیبانی میکنند که زیر ویژگی محفوظ system گروهبندی شدهاند:
- ServerProxy.system.listMethods()¶
این متد فهرستی از رشتهها را برمیگرداند، یکی برای هر متد (غیرسیستمی) که توسط سرور XML-RPC پشتیبانی میشود.
- ServerProxy.system.methodSignature(name)¶
این متد یک پارامتر میگیرد، نام متدی که توسط سرور XML-RPC پیادهسازیشده است. این متد آرایهای از امضاهای ممکن برای این متد برمیگرداند. یک امضا آرایهای از نوعها است. اولین مورد از این نوعها، نوع بازگشتی متد است و بقیه، پارامترها هستند.
از آنجا که چندین امضا، یعنی سربارگذاری (overloading)، مجاز است، این متد بهجای تکنمونه، فهرستی از امضاها را برمیگرداند.
خود امضاها به پارامترهای سطح بالایی که یک متد انتظار دارد محدود میشوند. برای مثال، اگر متدی یک آرایه از ساختارها را بهعنوان پارامتر انتظار داشته باشد و یک رشته را برگرداند، امضای آن بهسادگی "string, array" است. اگر سه عدد صحیح را انتظار داشته باشد و یک رشته را برگرداند، امضای آن "string, int, int, int" است.
اگر هیچ امضایی برای متد تعریف نشده باشد، یک مقدار غیرآرایهای برگردانده میشود. در پایتون، این بدان معنا است که نوع مقدار برگرداندهشده چیزی غیر از فهرست خواهد بود.
- ServerProxy.system.methodHelp(name)¶
این متد یک پارامتر میگیرد، نام متدی که توسط سرور XML-RPC پیادهسازی شده است. این متد یک رشته مستندسازی برمیگرداند که کاربرد آن متد را توصیف میکند. اگر چنین رشتهای در دسترس نباشد، یک رشته خالی برگردانده میشود. رشته مستندسازی ممکن است حاوی نمادگذاری HTML باشد.
تغییر یافته در نسخهی 3.5: نمونههای ServerProxy از پروتکل context manager برای بستن انتقال زیرین پشتیبانی میکنند.
در ادامه یک مثال کاربردی آمده است. کد سرور:
from xmlrpc.server import SimpleXMLRPCServer
def is_even(n):
return n % 2 == 0
server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(is_even, "is_even")
server.serve_forever()
کد کلاینت برای سرور پیشین:
import xmlrpc.client
with xmlrpc.client.ServerProxy("http://localhost:8000/") as proxy:
print("3 is even: %s" % str(proxy.is_even(3)))
print("100 is even: %s" % str(proxy.is_even(100)))
اشیای DateTime¶
- class xmlrpc.client.DateTime¶
این کلاس را میتوان با ثانیههای سپریشده از مبدأ زمانی، یک تاپل زمانی، یک رشته زمان/تاریخ ISO 8601، یا یک نمونه
datetime.datetimeمقداردهی اولیه کرد. این کلاس متدهای زیر را دارد که عمدتاً برای استفاده داخلی توسط کد مارشالینگ/مارشالگشایی پشتیبانی میشوند:- decode(string)¶
یک رشته را بهعنوان مقدار زمانی جدید نمونه میپذیرد.
همچنین از برخی از عملگرهای توکار پایتون از طریق متدهای
مقایسه غنیو__repr__()پشتیبانی میکند.
در ادامه یک مثال کاربردی آمده است. کد سرور:
import datetime as dt
from xmlrpc.server import SimpleXMLRPCServer
import xmlrpc.client
def today():
today = dt.datetime.today()
return xmlrpc.client.DateTime(today)
server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(today, "today")
server.serve_forever()
کد کلاینت برای سرور پیشین:
import xmlrpc.client
import datetime as dt
proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
today = proxy.today()
# convert the ISO 8601 string to a datetime object
converted = dt.datetime.strptime(today.value, "%Y%m%dT%H:%M:%S")
print(f"Today: {converted.strftime('%d.%m.%Y, %H:%M')}")
اشیای Binary¶
- class xmlrpc.client.Binary¶
این کلاس میتواند از دادههای بایتی (که ممکن است شامل نویسههای NUL باشد) مقداردهی اولیه شود. دسترسی اصلی به محتوای یک شیء
Binaryاز طریق یک ویژگی فراهم میشود:- data¶
دادههای دودویی کپسولهشده توسط نمونهی
Binary. این دادهها بهصورت یک شیءbytesارائه میشوند.
اشیای
Binaryمتدهای زیر را دارند، که عمدتاً برای استفادهی داخلی توسط کد مارشالینگ/مارشالگشایی (marshalling/unmarshalling) پشتیبانی میشوند:- decode(bytes)¶
یک شیء
bytesبا کدگذاری base64 را میپذیرد و آن را بهعنوان دادهی جدید نمونه کدگشایی میکند.
- encode(out)¶
کدگذاری base 64 مربوط به XML-RPC برای این آیتم دودویی را در شیء جریان out بنویسید.
دادههای کدگذاریشده مطابق RFC 2045 section 6.8، که در زمان نگارش مشخصات XML-RPC مشخصات استاندارد دوفاکتو (de facto) برای base64 بود، هر ۷۶ نویسه یک خط جدید خواهند داشت.
همچنین از برخی از عملگرهای توکار پایتون از طریق متدهای
__eq__()و__ne__()پشتیبانی میکند.
نمونه کاربرد اشیای دودویی. میخواهیم یک تصویر را از طریق XMLRPC منتقل کنیم:
from xmlrpc.server import SimpleXMLRPCServer
import xmlrpc.client
def python_logo():
with open("python_logo.jpg", "rb") as handle:
return xmlrpc.client.Binary(handle.read())
server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(python_logo, 'python_logo')
server.serve_forever()
کلاینت تصویر را دریافت میکند و آن را در یک پرونده ذخیره میکند:
import xmlrpc.client
proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
with open("fetched_python_logo.jpg", "wb") as handle:
handle.write(proxy.python_logo().data)
اشیای Fault¶
- class xmlrpc.client.Fault¶
یک شیء
Faultمحتوای برچسب fault در XML-RPC را در بر میگیرد. اشیای Fault دارای ویژگیهای زیر هستند:- faultCode¶
یک عدد صحیح که نوع خطا را نشان میدهد.
- faultString¶
رشتهای حاوی پیام تشخیصی مرتبط با خطا.
در مثال زیر، عمداً با برگرداندن یک شیء با نوع پیچیده، باعث ایجاد Fault میشویم. کد سرور:
from xmlrpc.server import SimpleXMLRPCServer
# A marshalling error is going to occur because we're returning a
# complex number
def add(x, y):
return x+y+0j
server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(add, 'add')
server.serve_forever()
کد کلاینت برای سرور پیشین:
import xmlrpc.client
proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
try:
proxy.add(2, 5)
except xmlrpc.client.Fault as err:
print("A fault occurred")
print("Fault code: %d" % err.faultCode)
print("Fault string: %s" % err.faultString)
اشیای ProtocolError¶
- class xmlrpc.client.ProtocolError¶
یک شیء
ProtocolErrorیک خطای پروتکل در لایهی انتقال زیرین را توصیف میکند (مانند خطای ۴۰۴ «یافت نشد» در صورتی که سرور مشخصشده با URI وجود نداشته باشد). این شیء دارای ویژگیهای زیر است:- url¶
URI یا URLی که باعث ایجاد خطا شد.
- errcode¶
کد خطا.
- errmsg¶
پیام خطا یا رشتهی تشخیصی.
- headers¶
یک دیکشنری شامل سرآیندهای درخواست HTTP/HTTPS که باعث ایجاد خطا شده است.
در مثال زیر، قصد داریم عمداً با ارائه یک URI نامعتبر، یک ProtocolError ایجاد کنیم:
import xmlrpc.client
# create a ServerProxy with a URI that doesn't respond to XMLRPC requests
proxy = xmlrpc.client.ServerProxy("http://google.com/")
try:
proxy.some_method()
except xmlrpc.client.ProtocolError as err:
print("A protocol error occurred")
print("URL: %s" % err.url)
print("HTTP/HTTPS headers: %s" % err.headers)
print("Error code: %d" % err.errcode)
print("Error message: %s" % err.errmsg)
اشیای MultiCall¶
شیء MultiCall راهی برای کپسولهکردن چندین فراخوانی به یک سرور دوردست در قالب یک درخواست فراهم میکند [1].
- class xmlrpc.client.MultiCall(server)¶
یک شیء برای دستهبندی (boxcar) فراخوانیهای متد ایجاد میکند. server هدف نهایی فراخوانی است. میتوان فراخوانیهایی را روی شیء نتیجه انجام داد، اما آنها بلافاصله
Noneرا بازمیگردانند و فقط نام و پارامترهای فراخوانی را در شیءMultiCallذخیره میکنند. فراخوانی خود شیء باعث میشود همهی فراخوانیهای ذخیرهشده در قالب یک درخواستsystem.multicallارسال شوند. نتیجهی این فراخوانی یک تولیدگر است؛ پیمایش روی این تولیدگر نتایج جداگانه را بازمیگرداند.
در ادامه مثالی از استفاده از این کلاس آمده است. کد سرور:
from xmlrpc.server import SimpleXMLRPCServer
def add(x, y):
return x + y
def subtract(x, y):
return x - y
def multiply(x, y):
return x * y
def divide(x, y):
return x // y
# A simple server with simple arithmetic functions
server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_multicall_functions()
server.register_function(add, 'add')
server.register_function(subtract, 'subtract')
server.register_function(multiply, 'multiply')
server.register_function(divide, 'divide')
server.serve_forever()
کد کلاینت برای سرور پیشین:
import xmlrpc.client
proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
multicall = xmlrpc.client.MultiCall(proxy)
multicall.add(7, 3)
multicall.subtract(7, 3)
multicall.multiply(7, 3)
multicall.divide(7, 3)
result = multicall()
print("7+3=%d, 7-3=%d, 7*3=%d, 7//3=%d" % tuple(result))
توابع کمکی¶
- xmlrpc.client.dumps(params, methodname=None, methodresponse=None, encoding=None, allow_none=False)¶
params را به یک درخواست XML-RPC، یا در صورتی که methodresponse true باشد، به یک پاسخ تبدیل میکند. params میتواند یک تاپل از آرگومانها یا نمونهای از کلاس استثنای
Faultباشد. اگر methodresponse true باشد، تنها یک مقدار میتواند برگردانده شود، به این معنا که params باید طول ۱ داشته باشد. encoding، در صورت ارائه، کدگذاری مورد استفاده در XML تولیدشده است؛ پیشفرض UTF-8 است. مقدارNoneپایتون نمیتواند در XML-RPC استاندارد استفاده شود؛ برای مجاز کردن استفاده از آن از طریق یک افزونه، یک مقدار true برای allow_none ارائه دهید.
- xmlrpc.client.loads(data, use_datetime=False, use_builtin_types=False)¶
یک درخواست یا پاسخ XML-RPC را به اشیای پایتون تبدیل میکند: یک
(params, methodname). params یک تاپل از آرگومانها است؛ methodname یک رشته است، یا اگر نام متدی در بسته وجود نداشته باشدNoneاست. اگر بستهی XML-RPC نشاندهندهی یک وضعیت خطا باشد، این تابع استثنایFaultرا پرتاب میکند. میتوان از پرچم use_builtin_types استفاده کرد تا مقادیر تاریخ/زمان بهصورت اشیایdatetime.datetimeو دادههای دودویی بهصورت اشیایbytesارائه شوند؛ این پرچم بهطور پیشفرض نادرست است.پرچم منسوخ use_datetime مشابه use_builtin_types است، اما فقط به مقادیر تاریخ/زمان اعمال میشود.
تغییر یافته در نسخهی 3.3: پرچم use_builtin_types افزوده شد.
نمونهای از استفادهی کلاینت¶
# simple test program (from the XML-RPC specification)
from xmlrpc.client import ServerProxy, Error
# server = ServerProxy("http://localhost:8000") # local server
with ServerProxy("http://betty.userland.com") as proxy:
print(proxy)
try:
print(proxy.examples.getStateName(41))
except Error as v:
print("ERROR", v)
برای دسترسی به یک سرور XML-RPC از طریق یک پراکسی HTTP، باید یک انتقال سفارشی تعریف کنید. مثال زیر نشان میدهد که چگونه:
import http.client
import xmlrpc.client
class ProxiedTransport(xmlrpc.client.Transport):
def set_proxy(self, host, port=None, headers=None):
self.proxy = host, port
self.proxy_headers = headers
def make_connection(self, host):
connection = http.client.HTTPConnection(*self.proxy)
connection.set_tunnel(host, headers=self.proxy_headers)
self._connection = host, connection
return connection
transport = ProxiedTransport()
transport.set_proxy('proxy-server', 8080)
server = xmlrpc.client.ServerProxy('http://betty.userland.com', transport=transport)
print(server.examples.getStateName(41))
مثالی از استفادهی کلاینت و سرور¶
مثال SimpleXMLRPCServer را ببینید.
پانویسها