程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python 開發與測試 Webservice(SOAP)-Win

編輯:Python

WebService是一種跨編程語言和跨操作系統平台的遠程調用技術。


> 理解webservice

1.從表面上看,WebService就是一個應用程序向外界暴露出一個能通過Web進行調用的API,也就是說能用編程的方法通過Web來調用這個應用程序。我們把調用這個WebService的應用程序叫做客戶端,而把提供這個WebService的應用程序叫做服務端。

2.從深層次看,WebService是建立可互操作的分布式應用程序的新平台,是一個平台,是一套標准。它定義了應用程序如何在Web上實現互操作性,你可以用任何你喜歡的語言,在任何你喜歡的平台上寫Web service ,只要我們可以通過Web service標准對這些服務進行查詢和訪問。

3.Web Service是一個平台獨立的,低耦合的,自包含的、基於可編程的web的應用程序,可使用開放的XML(標准通用標記語言下的一個子集)標准來描述、發布、發現、協調和配置這些應用程序,用於開發分布式的交互操作的應用程序。 [1]

4.Web Service技術, 能使得運行在不同機器上的不同應用無須借助附加的、專門的第三方軟件或硬件, 就可相互交換數據或集成。依據Web Service規范實施的應用之間, 無論它們所使用的語言、 平台或內部協議是什麼, 都可以相互交換數據。Web Service是自描述、 自包含的可用網絡模塊, 可以執行具體的業務功能。Web Service也很容易部署, 因為它們基於一些常規的產業標准以及已有的一些技術,諸如標准通用標記語言下的子集XML、HTTP。Web Service減少了應用接口的花費。Web Service為整個企業甚至多個組織之間的業務流程的集成提供了一個通用機制。

> Web服務的三個核心

  • 1、Soap:
    SOAP(Simple Object Access Protocol,簡單對象訪問協議)是一個基於xml的協議,用於在分步的應用程序都可以識別。另外,SOAP本身沒有定義任何程序語言,這使得SOAP能夠以消息的形式傳遞到各種遠程系統中。

    SOAP所使用的傳輸協議,可以是HTTP,SMTP,POP3,JMS。

    SOAP包括了4部分:
    01.“SOAP封裝(Envelope)”:
    定義一個描述信息描述的內容是什麼,是誰發送的,誰應當處理他,以及如何處理他們的框架。

    02.“SOAP編碼規則”:
    用於表示應用程序需要使用的數據類型的實例。

    03.“SOAP RPC":
    表示遠程過程中調用和應答的協定。

    04.“SOPA綁定”:
    使用底層協議交換信息。

  • 2.WSDL:
    WSDL(Web Service Description Language,web服務描述語言)是一個XML文檔,他以一種和具體語言無關的抽象方式定義了給定web服務收發者的有關操作和消息。

  • 3.UDDI:
    UDDI(Universal Description Discovery and Integration,統一描述發現和集成協議)是一個規范,定義了與web服務相關的信息的發布,發現和管理。
    END

> 看懂wsdl文件

只有看懂wsdl文件才能去調用soap類型的web服務,下面以YCS項目為例子的wsdl文件:

解釋:首先我們可以看到服務的地址為:http://47.106.68.247/ycsyth/webservices/ycsbizService,對應wsdl文件的地址為http://47.106.68.247/ycsyth/webservices/ycsbizService?wsdl,地址的前綴為soap,說明這個服務是基於soap1.1版本的,然後我們可以看到服務的名稱為IYcsBizServiceService,IYcsBizServiceService綁定的Port為IYcsBizServicePort,然後我們找到IYcsBizServicePort綁定的類型為IYcsBizService(portType name=“IYcsBizService”),從IYcsBizService中我們可以看到,支持一個方法叫做doService,關於doService的具體參數的信息看complexType name=“doService”。

> Python 庫選擇

服務端開發:

針對Python的WebService開發,開發者討論最多的庫是soaplib(官方地址:http://soaplib.github.io/soaplib/2_0/index.html),但從其官網可知,其最新版本“soaplib-2.0.0-beta2”從2011年3月發布後就不再進行更新了。通過閱讀soaplib的官方文檔,可知其不再維護後已經轉向了一個新的項目:rpclib(官方地址:http://github.com/arskom/rpclib)進行後續開發,但在rpclib的readme中,介紹了rpclib已經更名為spyne,並將持續進行更新,so,那就選用spyne進行開發了。

spyne 官方文檔:http://spyne.io/docs/2.10/index.html

spyne github:https://github.com/arskom/spyne

  • spyne 安裝:
pip install spyne
  • lxml 安裝:
pip install lxml

或者下載與python匹配的版本安裝包 https://pypi.python.org/pypi/lxml/3.6.0 進行安裝,如 lxml-3.6.0.win-amd64-py2.7.exe (md5)

客戶端開發

客戶端調用WebService一般應用suds庫。

使用參考文檔:https://fedorahosted.org/suds/wiki/Documentation

  • suds 安裝:
pip install suds

> 知識拓展

Spyne Introduction

  • Protocols:協議
  • Protocols define the rules for transmission of structured data
  • Transports:傳輸
  • Transports, also protocols themselves, encapsulate protocol data in their free-form data sections.
  • Models:模式
  • Types like Unicode, Integer or ByteArray are all models. They reside in the spyne.model package.
  • Interface Documents:接口文檔
  • Interface documents provide a machine-readable description of the expected input and output of the exposed method calls.
  • Serializers:序列化對象
  • Serializers are currently not distinguished in Spyne code. They are the protocol-specific representations of a serialized Python object.

How your code is wrapped?

  • step1:

  • Your code is inside @rpc-wrapped methods in ServiceBase subclasses.

  • step2:

  • The ServiceBase subclasses in turn are wrapped by an Application instance.

  • The Application instantiation is used to assign input and output protocols to the exposed methods.

  • step3:

  • The Application instance is finally wrapped by a client or server transport that takes the responsibility of moving the bits around.

  • step4:

  • Deploying the service using Soap via Wsgi


> 代碼實例–(結構1)

目錄結構

webservice
client.py
serve.py

使用Python實現服務端

server.py 服務端啟動文件
# -*- coding: utf-8 -*-
"""
preference:
http://spyne.io/docs/2.10/index.html
https://github.com/arskom/spyne/blob/master/examples/helloworld_soap.py
This is a simple HelloWorld example to show the basics of writing
a webservice using spyne, starting a server, and creating a service
client.
Here's how to call it using suds:
#>>> from suds.client import Client
#>>> hello_client = Client('http://localhost:8000/?wsdl')
#>>> hello_client.service.say_hello('punk', 5)
(stringArray){
string[] =
"Hello, punk",
"Hello, punk",
"Hello, punk",
"Hello, punk",
"Hello, punk",
}
#>>>
"""
# Application is the glue between one or more service definitions, interface and protocol choices.
from spyne import Application
# @rpc decorator exposes methods as remote procedure calls
# and declares the data types it accepts and returns
from spyne import rpc
# spyne.service.ServiceBase is the base class for all service definitions.
from spyne import ServiceBase
# The names of the needed types for implementing this service should be self-explanatory.
from spyne import Iterable, Integer, Unicode
from spyne.protocol.soap import Soap11
# Our server is going to use HTTP as transport, It’s going to wrap the Application instance.
from spyne.server.wsgi import WsgiApplication
# step1: Defining a Spyne Service
class HelloWorldService(ServiceBase):
@rpc(Unicode, Integer, _returns=Iterable(Unicode))
def say_hello(self, name, times):
"""Docstrings for service methods appear as documentation in the wsdl.
<b>What fun!</b>
@param name: the name to say hello to
@param times: the number of times to say hello
@return When returning an iterable, you can use any type of python iterable. Here, we chose to use generators.
"""
for i in range(times):
yield u'Hello, %s' % name
# step2: Glue the service definition, input and output protocols
soap_app = Application([HelloWorldService], 'spyne.examples.hello.soap',
in_protocol=Soap11(validator='lxml'),
out_protocol=Soap11())
# step3: Wrap the Spyne application with its wsgi wrapper
wsgi_app = WsgiApplication(soap_app)
if __name__ == '__main__':
import logging
from wsgiref.simple_server import make_server
# configure the python logger to show debugging output
# logging.basicConfig(level=logging.DEBUG)
# logging.getLogger('spyne.protocol.xml').setLevel(logging.DEBUG)
# logging.info("listening to http://127.0.0.1:8000")
# logging.info("wsdl is at: http://localhost:8000/?wsdl")
# step4:Deploying the service using Soap via Wsgi
# register the WSGI application as the handler to the wsgi server, and run the http server
print('WebService Started')
server = make_server('127.0.0.1', 8000, wsgi_app)
server.serve_forever()

檢查服務

服務端運行後,

訪問浏覽器檢查服務 http://localhost:8000/?wsdl

浏覽器中輸出wsdl文件:

使用Python實現客戶端

client.py 客戶端接口
# -*- coding: utf-8 -*-
from suds.client import Client # 導入suds.client 模塊下的Client類
wsdl_url = "http://localhost:8000/?wsdl"
def say_hello_test(url, name, times):
client = Client(url) # 創建一個webservice接口對象
resp = client.service.say_hello(name, times)
print(resp)
# client.service.say_hello(name, times) # 調用這個接口下的getMobileCodeInfo方法,並傳入參數
# req = str(client.last_sent()) # 保存請求報文,因為返回的是一個實例,所以要轉換成str
# response = str(client.last_received()) # 保存返回報文,返回的也是一個實例
# print (req) # 打印請求報文
# print (response) # 打印返回報文
if __name__ == '__main__':
say_hello_test(wsdl_url, 'Milton', 2)

接口測試

啟動服武器

執行客戶端

客戶端結果如下

(stringArray){
string[] =
"Hello, Milton",
"Hello, Milton",
}

> 代碼實例–(結構2)

目錄結構

webservice
client
client.py
server
app.py
service.py

使用Python實現服務端

service.py 服務端啟動文件
# -*- coding: utf-8 -*-
"""
preference:
http://spyne.io/docs/2.10/index.html
https://github.com/arskom/spyne/blob/master/examples/helloworld_soap.py
This is a simple HelloWorld example to show the basics of writing
a webservice using spyne, starting a server, and creating a service
client.
Here's how to call it using suds:
#>>> from suds.client import Client
#>>> hello_client = Client('http://localhost:8000/?wsdl')
#>>> hello_client.service.say_hello('punk', 5)
(stringArray){
string[] =
"Hello, punk",
"Hello, punk",
"Hello, punk",
"Hello, punk",
"Hello, punk",
}
#>>>
"""
import json
import os
# Application is the glue between one or more service definitions, interface and protocol choices.
# 應用程序是一個或多個服務定義、接口和協議選擇之間的粘合劑
from spyne import Application
# @rpc decorator exposes methods as remote procedure calls 裝飾器將方法公開為遠程過程調用
# and declares the data types it accepts and returns 並聲明它接受和返回的數據類型
from spyne import rpc
# spyne.service.ServiceBase is the base class for all service definitions.
from spyne import ServiceBase
# The names of the needed types for implementing this service should be self-explanatory.
# 實現該服務所需類型的名稱應該是不言自明的
from spyne import Iterable, Integer, Unicode
from spyne.protocol.soap import Soap11
# Our server is going to use HTTP as transport, It’s going to wrap the Application instance.
from spyne.server.wsgi import WsgiApplication
from app import PyWebService #注意:此處引用app.py文件內的PyWebService類
#step1: Defining a Spyne Service
# class PyWebService(ServiceBase):
# @rpc(Unicode, Integer, _returns=Iterable(Unicode))
# def say_hello(self, name, times):
# """Docstrings for service methods appear as documentation in the wsdl.
# <b>What fun!</b>
# @param name: the name to say hello to
# @param times: the number of times to say hello
# @return When returning an iterable, you can use any type of python iterable. Here, we chose to use generators.
# """
# for i in range(times):
# return u'Hello, %s' % name
# step2: Glue the service definition, input and output protocols
soap_app = Application([PyWebService], 'PyWebService',
in_protocol=Soap11(validator='lxml'),
out_protocol=Soap11())
# step3: Wrap the Spyne application with its wsgi wrapper
wsgi_app = WsgiApplication(soap_app)
if __name__ == '__main__':
import logging
from wsgiref.simple_server import make_server
# configure the python logger to show debugging output
# logging.basicConfig(level=logging.DEBUG)
# logging.getLogger('spyne.protocol.xml').setLevel(logging.DEBUG)
# logging.info("listening to http://127.0.0.1:8000")
# logging.info("wsdl is at: http://localhost:8000/?wsdl")
host = "127.0.0.1"
port = 8000
# step4:Deploying the service using Soap via Wsgi
# register the WSGI application as the handler to the wsgi server, and run the http server
server = make_server(host, port, wsgi_app)
print('WebService Started')
print('http://' + host + ':' + str(port) + '/?wsdl')
server.serve_forever()
app.py webservice接口
# -*- coding: utf-8 -*-
import json
from spyne import ServiceBase, rpc, Double
from spyne import Integer, Unicode, String, Iterable
class User(object):
def __init__(self, age, user_name):
self.age = age
self.user_name = user_name
self.sex = 0
def get_user_list(self, current_page, page_size):
l = []
for i in range(10):
l.append({'age': self.age, 'sex': self.sex, 'user_name': self.user_name})
return l
user_mgr = User(18, 'Tom')
class PyWebService(ServiceBase):
...
@rpc(Unicode, Integer, _returns=Iterable(Unicode))
def say_hello(self, name, times):
"""Docstrings for service methods appear as documentation in the wsdl.
<b>What fun!</b>
@param name: the name to say hello to
@param times: the number of times to say hello
@return When returning an iterable, you can use any type of python iterable. Here, we chose to use generators.
"""
for i in range(times):
return u'Hello, %s' % name
@rpc(_returns=Unicode)
def get_version(self):
"""
獲取系統版本
:return:
"""
return json.dumps({'version': 1.0})
@rpc(Integer, Integer, _returns=Unicode)
def get_user_list(self, current_page, page_size):
"""
獲取用戶列表
:return:
"""
return json.dumps(user_mgr.get_user_list(current_page, page_size))

檢查服務

服務端運行後,

訪問浏覽器檢查服務 http://localhost:8000/?wsdl

浏覽器中輸出wsdl文件:

使用Python實現客戶端

client.py 客戶端接口
# -*- coding: utf-8 -*-
import json
from suds.client import Client # 導入suds.client 模塊下的Client類
wsdl_url = "http://localhost:8000/?wsdl"
def client_operation(url, name, times):
client = Client(url) # 創建一個webservice接口對象
print(client) #查看定義的所有方法與請求所需攜帶的參數,返回的Methods中即定義的方法,包括請求所需攜帶的參數與參數類型。
resp = client.service.get_version() # 調用這個接口下的get_version方法,無參數
print(json.loads(resp))
resp1 = client.service.say_hello(name, times) # 調用這個接口下的getMobileCodeInfo方法,並傳入參數
print(str(resp1))
resp2 = client.service.get_user_list(3,4)
print(json.loads(resp2))
if __name__ == '__main__':
client_operation(wsdl_url, 'Milton', 2)

接口測試

啟動服武器

執行客戶端

客戶端結果如下

Suds ( https://fedorahosted.org/suds/ ) version: 1.1.1
Service ( PyWebService ) tns="PyWebService"
Prefixes (1)
ns0 = "PyWebService"
Ports (1):
(Application)
Methods (3):
get_user_list(xs:integer current_page, xs:integer page_size)
get_version()
say_hello(xs:string name, xs:integer times)
Types (7):
get_user_list
get_user_listResponse
get_version
get_versionResponse
say_hello
say_helloResponse
stringArray
{'version': 1.0}
(stringArray){
string[] =
"H",
"e",
"l",
"l",
"o",
",",
" ",
"M",
"i",
"l",
"t",
"o",
"n",
}
[{'age': 18, 'sex': 0, 'user_name': 'Tom'}, {'age': 18, 'sex': 0, 'user_name': 'Tom'}, {'age': 18, 'sex': 0, 'user_name': 'Tom'}, {'age': 18, 'sex': 0, 'user_name': 'Tom'}, {'age': 18, 'sex': 0, 'user_name': 'Tom'}, {'age': 18, 'sex': 0, 'user_name': 'Tom'}, {'age': 18, 'sex': 0, 'user_name': 'Tom'}, {'age': 18, 'sex': 0, 'user_name': 'Tom'}, {'age': 18, 'sex': 0, 'user_name': 'Tom'}, {'age': 18, 'sex': 0, 'user_name': 'Tom'}]

參考連接:
http://47.106.68.247/ycsyth/webservices/ycsbizService?wsdl
https://blog.csdn.net/qq_33196814/article/details/122303882
https://www.cnblogs.com/guanfuchang/p/5985070.html


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved