# `xmlrpc.server` --- 基本 XML-RPC 伺服器

原始碼：Lib/xmlrpc/server.py

`xmlrpc.server` 模組為以 Python 撰寫的 XML-RPC 伺服器提供了基本的伺服器框架。伺服器可以是獨立執行的（使用 `SimpleXMLRPCServer`），或嵌入在 CGI 環境中（使用 `CGIXMLRPCRequestHandler`）。

警告

`xmlrpc.server` 模組對於惡意建構的資料並不安全。如果你需要剖析不受信任或未經驗證的資料，請參閱 XML 安全性。

可用性: not WASI.

此模組在 WebAssembly 平台上不起作用或無法使用。更多資訊請參閱 WebAssembly 平台。

class xmlrpc.server.SimpleXMLRPCServer(addr, requestHandler=SimpleXMLRPCRequestHandler, logRequests=True, allow_none=False, encoding=None, bind_and_activate=True, use_builtin_types=False)

  建立一個新的伺服器實例。此類別提供了可被 XML-RPC 協定呼叫之函式的註冊方法。requestHandler 參數應該是請求處理器實例的工廠（factory）；它預設為 `SimpleXMLRPCRequestHandler`。addr 和 requestHandler 參數會傳遞給 `socketserver.TCPServer` 建構函式。如果 logRequests 為 true（預設值），請求會被記錄；將此參數設定為 false 將關閉記錄。allow_none 和 encoding 參數會傳遞給 `xmlrpc.client` 並控制從伺服器回傳的 XML-RPC 回應。bind_and_activate 參數控制建構函式是否立即呼叫 `server_bind()` 和 `server_activate()`；它預設為 true。將其設定為 false 允許程式碼在位址被綁定之前操作 allow_reuse_address 類別變數。use_builtin_types 參數會傳遞給 `loads()` 函式，並控制在接收到日期/時間值或二進位資料時要處理哪些型別；它預設為 false。

  在 3.3 版的變更: 新增 use_builtin_types 旗標。

class xmlrpc.server.CGIXMLRPCRequestHandler(allow_none=False, encoding=None, use_builtin_types=False)

  建立一個新的實例以在 CGI 環境中處理 XML-RPC 請求。allow_none 和 encoding 參數會傳遞給 `xmlrpc.client` 並控制從伺服器回傳的 XML-RPC 回應。use_builtin_types 參數會傳遞給 `loads()` 函式，並控制在接收到日期/時間值或二進位資料時要處理哪些型別；它預設為 false。

  在 3.3 版的變更: 新增 use_builtin_types 旗標。

class xmlrpc.server.SimpleXMLRPCRequestHandler

  建立一個新的請求處理器實例。此請求處理器支援 `POST` 請求，並修改日誌記錄功能以遵守 `SimpleXMLRPCServer` 建構函式的 logRequests 參數。

## SimpleXMLRPCServer 物件

`SimpleXMLRPCServer` 類別是基於 `socketserver.TCPServer` 的，並提供了建立簡單、獨立 XML-RPC 伺服器的方式。

SimpleXMLRPCServer.register_function(function=None, name=None)

  註冊一個可以回應 XML-RPC 請求的函式。如果有給定 name，它將成為與 function 關聯的方法名稱，否則將使用 `function.__name__`。name 是一個字串，可以包含在 Python 識別符中不合法的字元，包括句點字元。

  此方法也可以用作裝飾器。當用作裝飾器時，name 只能作為關鍵字引數給定，以在 name 下註冊 function。如果沒有給定 name，將使用 `function.__name__`。

  在 3.7 版的變更: `register_function()` 也可被當作裝飾器使用。

SimpleXMLRPCServer.register_instance(instance, allow_dotted_names=False)

  註冊一個物件，用於公開尚未使用 `register_function()` 註冊的方法名稱。如果 instance 包含 `_dispatch()` 方法，它會被呼叫並傳入請求的方法名稱和來自請求的參數。其 API 為 `def _dispatch(self, method, params)`（注意 params 不代表可變引數列表）。如果它呼叫底層函式來執行其任務，該函式會以 `func(*params)` 的方式被呼叫，展開參數列表。來自 `_dispatch()` 的回傳值會作為結果回傳給用戶端。如果 instance 沒有 `_dispatch()` 方法，則會搜尋與請求方法名稱匹配的屬性。

  如果可選的 allow_dotted_names 引數為 true 且實例沒有 `_dispatch()` 方法，那麼如果請求的方法名稱包含句點，方法名稱的每個組成部分會被單獨搜尋，從而執行簡單的階層式搜尋。從此搜尋中找到的值會以來自請求的參數被呼叫，並將回傳值傳回給用戶端。

  警告

  啟用 allow_dotted_names 選項允許入侵者存取你模組的全域變數，並可能允許入侵者在你的機器上執行任意程式碼。請在安全、封閉的網路上才使用此選項。

SimpleXMLRPCServer.register_introspection_functions()

  註冊 XML-RPC 自我檢查函式 (introspection functions) `system.listMethods`、`system.methodHelp` 和 `system.methodSignature`。

SimpleXMLRPCServer.register_multicall_functions()

  註冊 XML-RPC 多重呼叫函式 (multicall function) system.multicall。

SimpleXMLRPCRequestHandler.rpc_paths

  一個屬性值，必須是一個元組，列出接收 XML-RPC 請求的 URL 的有效路徑部分。發布到其他路徑的請求將導致 404 "no such page" HTTP 錯誤。如果此元組為空，所有路徑都將被視為有效。預設值為 `('/', '/RPC2')`。

### SimpleXMLRPCServer 範例

伺服器程式碼：

    from xmlrpc.server import SimpleXMLRPCServer
    from xmlrpc.server import SimpleXMLRPCRequestHandler

    # 限制為特定路徑。
    class RequestHandler(SimpleXMLRPCRequestHandler):
        rpc_paths = ('/RPC2',)

    # 建立伺服器
    with SimpleXMLRPCServer(('localhost', 8000),
                            requestHandler=RequestHandler) as server:
        server.register_introspection_functions()

        # 註冊 pow() 函式；這將使用 pow.__name__ 的值作為名稱，即 'pow'。
        server.register_function(pow)

        # 以不同的名稱註冊函式
        def adder_function(x, y):
            return x + y
        server.register_function(adder_function, 'add')

        # 註冊一個實例；該實例的所有方法都會被發布為 XML-RPC 方法（在此例中僅 'mul'）。
        class MyFuncs:
            def mul(self, x, y):
                return x * y

        server.register_instance(MyFuncs())

        # 執行伺服器的主迴圈
        server.serve_forever()

以下用戶端程式碼將呼叫前述伺服器提供的方法：

    import xmlrpc.client

    s = xmlrpc.client.ServerProxy('http://localhost:8000')
    print(s.pow(2,3))  # 回傳 2**3 = 8
    print(s.add(2,3))  # 回傳 5
    print(s.mul(5,2))  # 回傳 5*2 = 10

    # 印出可用方法列表
    print(s.system.listMethods())

`register_function()` 也可以用作裝飾器。前述的伺服器範例可以用裝飾器方式註冊函式：

    from xmlrpc.server import SimpleXMLRPCServer
    from xmlrpc.server import SimpleXMLRPCRequestHandler

    class RequestHandler(SimpleXMLRPCRequestHandler):
        rpc_paths = ('/RPC2',)

    with SimpleXMLRPCServer(('localhost', 8000),
                            requestHandler=RequestHandler) as server:
        server.register_introspection_functions()

        # 註冊 pow() 函式；這將使用 pow.__name__ 的值作為名稱，即 'pow'。
        server.register_function(pow)

        # 使用 register_function 作為裝飾器以不同的名稱註冊函式。
        # *name* 只能作為關鍵字引數給定。
        @server.register_function(name='add')
        def adder_function(x, y):
            return x + y

        # 以 function.__name__ 註冊函式。
        @server.register_function
        def mul(x, y):
            return x * y

        server.serve_forever()

以下包含在 `Lib/xmlrpc/server.py` 模組中的範例展示了一個允許點分隔名稱並註冊多重呼叫函式的伺服器。

警告

啟用 allow_dotted_names 選項來允許入侵者存取你模組的全域變數，並可能允許入侵者在你的機器上執行任意程式碼。請在安全、封閉的網路中才使用此範例。

    import datetime as dt

    class ExampleService:
        def getData(self):
            return '42'

        class currentTime:
            @staticmethod
            def getCurrentTime():
                return dt.datetime.now()

    with SimpleXMLRPCServer(("localhost", 8000)) as server:
        server.register_function(pow)
        server.register_function(lambda x,y: x+y, 'add')
        server.register_instance(ExampleService(), allow_dotted_names=True)
        server.register_multicall_functions()
        print('Serving XML-RPC on localhost port 8000')
        try:
            server.serve_forever()
        except KeyboardInterrupt:
            print("\nKeyboard interrupt received, exiting.")
            sys.exit(0)

此 ExampleService 示範可以從命令列觸發：

    python -m xmlrpc.server

與上述伺服器互動的用戶端被包含在 `Lib/xmlrpc/client.py` 中：

    server = ServerProxy("http://localhost:8000")

    try:
        print(server.currentTime.getCurrentTime())
    except Error as v:
        print("ERROR", v)

    multi = MultiCall(server)
    multi.getData()
    multi.pow(2,9)
    multi.add(1,2)
    try:
        for response in multi():
            print(response)
    except Error as v:
        print("ERROR", v)

與示範 XMLRPC 伺服器互動的此用戶端可以如下呼叫：

    python -m xmlrpc.client

## CGIXMLRPCRequestHandler

`CGIXMLRPCRequestHandler` 類別可用於處理發送到 Python CGI 指令稿的 XML-RPC 請求。

CGIXMLRPCRequestHandler.register_function(function=None, name=None)

  註冊一個可以回應 XML-RPC 請求的函式。如果有給定 name，它將成為與 function 關聯的方法名稱，否則將使用 `function.__name__`。name 是一個字串，可以包含在 Python 識別符中不合法的字元，包括句點字元。

  此方法也可以用作裝飾器。當用作裝飾器時，name 只能作為關鍵字引數給定，以在 name 下註冊 function。如果沒有給定 name，將使用 `function.__name__`。

  在 3.7 版的變更: `register_function()` 也可被當作裝飾器使用。

CGIXMLRPCRequestHandler.register_instance(instance)

  註冊一個物件，用於公開尚未使用 `register_function()` 註冊的方法名稱。如果實例包含 `_dispatch()` 方法，它會以請求的方法名稱和來自請求的參數來被呼叫；回傳值會作為結果回傳給用戶端。如果實例沒有 `_dispatch()` 方法，則會搜尋與請求方法名稱匹配的屬性；如果請求的方法名稱包含句點，方法名稱的每個組成部分會被單獨搜尋，從而執行簡單的階層式搜尋。從此搜尋中找到的值會以來自請求的參數被呼叫，並將回傳值傳回給用戶端。

CGIXMLRPCRequestHandler.register_introspection_functions()

  註冊 XML-RPC 自我檢查函式 `system.listMethods`、`system.methodHelp` 和 `system.methodSignature`。

CGIXMLRPCRequestHandler.register_multicall_functions()

  註冊 XML-RPC 多重呼叫函式 `system.multicall`。

CGIXMLRPCRequestHandler.handle_request(request_text=None)

  處理 XML-RPC 請求。如果給定 request_text，它應該是 HTTP 伺服器提供的 POST 資料，否則將使用 stdin 的內容。

範例：

    class MyFuncs:
        def mul(self, x, y):
            return x * y

    handler = CGIXMLRPCRequestHandler()
    handler.register_function(pow)
    handler.register_function(lambda x,y: x+y, 'add')
    handler.register_introspection_functions()
    handler.register_instance(MyFuncs())
    handler.handle_request()

## 記錄 XMLRPC 伺服器

這些類別擴充了上述類別，來為 HTTP GET 請求於回應中提供 HTML 文件。伺服器可以是獨立執行的（使用 `DocXMLRPCServer`），或嵌入在 CGI 環境中（使用 `DocCGIXMLRPCRequestHandler`）。

class xmlrpc.server.DocXMLRPCServer(addr, requestHandler=DocXMLRPCRequestHandler, logRequests=True, allow_none=False, encoding=None, bind_and_activate=True, use_builtin_types=True)

  建立一個新的伺服器實例。所有參數的意義與 `SimpleXMLRPCServer` 相同；requestHandler 預設為 `DocXMLRPCRequestHandler`。

  在 3.3 版的變更: 新增 use_builtin_types 旗標。

class xmlrpc.server.DocCGIXMLRPCRequestHandler

  建立一個新的實例以在 CGI 環境中處理 XML-RPC 請求。

class xmlrpc.server.DocXMLRPCRequestHandler

  建立一個新的請求處理器實例。此請求處理器支援 XML-RPC POST 請求、文件 GET 請求，並修改日誌記錄功能以遵守 `DocXMLRPCServer` 建構函式的 logRequests 參數。

## DocXMLRPCServer 物件

`DocXMLRPCServer` 類別衍生自 `SimpleXMLRPCServer`，並提供了建立自我記錄 (self-documenting) 的獨立 XML-RPC 伺服器的方式。HTTP POST 請求會被作為 XML-RPC 方法呼叫來處理。HTTP GET 請求會透過產生 pydoc 風格的 HTML 文件來處理。這允許伺服器提供自己的網頁文件。

DocXMLRPCServer.set_server_title(server_title)

  設定在產生的 HTML 文件中使用的標題。此標題將用於 HTML "title" 元素內。

DocXMLRPCServer.set_server_name(server_name)

  設定在產生的 HTML 文件中使用的名稱。此名稱將顯示在產生的文件頂部的 "h1" 元素內。

DocXMLRPCServer.set_server_documentation(server_documentation)

  設定在產生的 HTML 文件中使用的描述。此描述將作為一個段落顯示在文件中伺服器名稱的下方。

## DocCGIXMLRPCRequestHandler

`DocCGIXMLRPCRequestHandler` 類別衍生自 `CGIXMLRPCRequestHandler`，並提供了建立自我記錄的 XML-RPC CGI 指令稿的方法。HTTP POST 請求會被作為 XML-RPC 方法呼叫來處理。HTTP GET 請求會透過產生 pydoc 風格的 HTML 文件來處理。這允許伺服器提供自己的網頁文件。

DocCGIXMLRPCRequestHandler.set_server_title(server_title)

  設定在產生的 HTML 文件中使用的標題。此標題將用於 HTML "title" 元素內。

DocCGIXMLRPCRequestHandler.set_server_name(server_name)

  設定在產生的 HTML 文件中使用的名稱。此名稱將顯示在產生的文件頂部的 "h1" 元素內。

DocCGIXMLRPCRequestHandler.set_server_documentation(server_documentation)

  設定在產生的 HTML 文件中使用的描述。此描述將作為一個段落顯示在文件中伺服器名稱的下方。