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

نوع پایتون

boolean

bool

int، i1، i2، i4، i8 یا biginteger

int در بازه‌ی -۲۱۴۷۴۸۳۶۴۸ تا ۲۱۴۷۴۸۳۶۴۷. مقادیر برچسب <int> را دریافت می‌کنند.

double یا float

float. مقادیر برچسب <double> را دریافت می‌کنند.

string

str

array

list یا tuple شامل عناصر سازگار. آرایه‌ها به‌صورت lists برگردانده می‌شوند.

struct

dict. کلیدها باید از جنس رشته باشند، مقادیر می‌توانند از هر نوع سازگار (conformable) باشند. می‌توان اشیایی از کلاس‌های تعریف‌شده توسط کاربر را نیز ارسال کرد؛ تنها ویژگی __dict__ آن‌ها منتقل می‌شود.

dateTime.iso8601

DateTime یا datetime.datetime. نوع برگردانده‌شده به مقادیر پرچم‌های use_builtin_types و use_datetime بستگی دارد.

base64

Binary، bytes یا bytearray. نوع بازگشتی به مقدار پرچم use_builtin_types بستگی دارد.

nil

ثابت None. ارسال آن فقط در صورتی مجاز است که allow_none درست باشد.

bigdecimal

decimal.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)

یک رشته را به‌عنوان مقدار زمانی جدید نمونه می‌پذیرد.

encode(out)

کدگذاری XML-RPC این آیتم DateTime را در شیء جریان out بنویسید.

همچنین از برخی از عملگرهای توکار پایتون از طریق متدهای مقایسه غنی و __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 را ببینید.

پانویس‌ها