一、用ladon框架封裝Python為Webservice接口
另用soaplib實現請看: http://www.jianshu.com/p/ad3c27d2a946
功能實現的同時,希望將接口開放給別人,而封裝python接口的一個再簡單不過的框架Ladon,而且提供不同的協議,包括SOAP和Json等格式的接口。本篇緊接着上上篇(Django部署)的。雖然很簡單,但是官網的文檔還是不夠詳細,下面介紹我配置的過程及遇到的問題。
1、安裝Ladon包
使用Ladon框架,首先需要安裝Ladon包(Ladon for Python),最新的是Ladon-0.8.9。
2、新建一個APP(接着上個項目的話,就取名叫appapi)
1)、在這個app下面新建一個文件handler.py(實際上就是一個views):
# Create your views here. from ladon.server.wsgi import LadonWSGIApplication import os os.environ['DJANGO_SETTINGS_MODULE'] = 'appops.settings' #這里是項目的名稱設置 application = LadonWSGIApplication( ['appapi.views'], #引用當前目錄下views里的內容 [os.path.join(os.path.dirname(__file__), os.path.pardir)], catalog_name='OPS APP API', catalog_desc='This is the root of my cool webservice catalog')
在Windows環境下,其實這時會報錯,報各種No modules named XXX的錯誤(上述from ladon.server.wsgi import LadonWSGIApplication 這句話需要三個包),這個好辦,缺什么包裝什么包,有個這個巨無霸Windows-Python集成包網站,啥都不缺,Ctrl+F就行!注意版本,這里很全,目前Windows下所有python的包都能在這里找到,32位和64位的都有,配置過程中,我就缺了下面三個包:
Jinja2-2.7.2.win32-py2.7.exe
MarkupSafe-0.18.win32-py2.7.exe
docutils-0.11.win32-py2.7.exe
2)、寫接口函數(就是APP下的Views.py里的內容),被上面引用的['appapi.views']
以一個加法和減法為例:
from ladon.ladonizer import ladonize from ladon.types.ladontype import LadonType class Calculator(object): @ladonize(int,int,rtype=int) def add(self,a,b): return a+b @ladonize(int,int,rtype=int) def Minus(self,a,b): return a-b class MyService(object): @ladonize(int,rtype=int) def mytest(self,a): return a*a
這里要注意兩點:
a、要封裝的方法必須寫在一個類里(如這里的Class XXX)
b、類下面的方法如果需要封裝,則方法前面必須加修飾符@ladonize,后面的參數分別是輸入參數的類型和輸出參數(return type)的類型
3、編輯配置文件
可以在apache_django_wsgi.conf文件里配置也可以在apache下的httpd.conf文件下配置,加上這句:
WSGIScriptAlias /api "D:/OPSAPP/appops/appapi/handler.py"
意思就是可以通過在主域名(或IP)后面加上/api/就可以訪問到接口,而不用在urls.py里的urlpattern里寫url了。
這里需要注意:
a、這句與WSGIScriptAlias / "D:/OPSAPP/django.wsgi"的順序,上述api的別名一定要放在django.wsgi引用的前面,否則導致/api/的頁面不能訪問(試了很多次,WSGIScriptAlias /api "D:/OPSAPP/appops/appapi/handler.py"這個配置在apache_django_wsgi.conf里有問題,會出現主頁和api頁面不能同時訪問的情況。但是有的同事就可以,不知道哪里配置不一樣。我是配置在httpd.conf里的)
b、如果不能訪問api頁面,錯誤日志會記錄在apache目錄下的logs/error.log里。配置過程中遇到了這個錯誤:assert sys.modules[modname] is old_mod
這個需要改動源碼:C:\Python27\Lib\site-packages\win32\lib\pywintypes.py第113行那段改動如下:
if sys.version_info < (3,0): # assert sys.modules[modname] is old_mod # assert mod is old_mod pass else: assert sys.modules[modname] is not old_mod assert sys.modules[modname] is mod # as above - re-reset to the *old* module object then update globs. sys.modules[modname] = old_mod globs.update(mod.__dict__)
注意:每當修改過配置文件或者代碼時,最好重啟下apache服務,不然可能頁面看不出改動后的效果。
至此沒問題了,訪問URL/api的界面如下:
點擊Calculator接口,他提供了不同格式的接口類型:
我常用的就是第一個soap11類型的接口,點進去如下(不明覺厲,有木有):
This XML file does not appear to have any style information associated with it. The document tree is shown below. <wsdl:definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:ns1="urn:Calculator" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="urn:Calculator" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Calculator" targetNamespace="urn:Calculator"> <wsdl:types> <xsd:schema xmlns:ns1="urn:Calculator" targetNamespace="urn:Calculator"> <xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/"/> </xsd:schema> </wsdl:types> <wsdl:message name="add"> <wsdl:part name="a" type="xsd:long"/> <wsdl:part name="b" type="xsd:long"/> </wsdl:message> <wsdl:message name="addResponse"> <wsdl:part name="result" type="xsd:long"/> </wsdl:message> <wsdl:message name="minus"> <wsdl:part name="a" type="xsd:long"/> <wsdl:part name="b" type="xsd:long"/> </wsdl:message> <wsdl:message name="minusResponse"> <wsdl:part name="result" type="xsd:long"/> </wsdl:message> <wsdl:portType name="CalculatorPortType"> <wsdl:operation name="add"> <wsdl:input message="tns:add"/> <wsdl:output message="tns:addResponse"/> </wsdl:operation> <wsdl:operation name="minus"> <wsdl:input message="tns:minus"/> <wsdl:output message="tns:minusResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="Calculator" type="tns:CalculatorPortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="add"> <soap:operation soapAction="http://192.168.18.74/api/Calculator/soap11/add" style="rpc"/> <wsdl:input> <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Calculator" use="encoded"/> </wsdl:input> <wsdl:output> <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Calculator" use="encoded"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="minus"> <soap:operation soapAction="http://192.168.18.74/api/Calculator/soap11/minus" style="rpc"/> <wsdl:input> <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Calculator" use="encoded"/> </wsdl:input> <wsdl:output> <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Calculator" use="encoded"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="Calculator"> <wsdl:documentation>Ladon generated service definition</wsdl:documentation> <wsdl:port binding="tns:Calculator" name="Calculator"> <soap:address location="http://192.168.18.74/api/Calculator/soap11"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
二、接口調用方法
1、調用Soap11的接口
需要安裝soap 的Client端包,大名叫做Suds(我的版本是suds-0.4),調用很簡單,如下一個示例,不解釋,聰明的你一看就明白:
#encoding:utf-8 import json # import urllib,urllib2 from suds.client import Client # import logging # logging.basicConfig(level=logging.INFO) # logging.getLogger('suds.client').setLevel(logging.DEBUG)
# username = 'api_user'
# password = 'api_pwd'
url="http://192.168.18.74/api/Calculator/soap11/description" #接口的URL headers = {'Content-Type': 'application/soap+xml; charset="UTF-8"'} client = Client(url,headers=headers,faults=False,timeout=15) def call_api_test(num1,num2): try: #--WSDL請求Header---------------------------------------------- # auth = client.factory.create('AuthenticationInfo') # auth.userName = username # auth.password = password # client.set_options(soapheaders=auth) #--WSDL請求Body---------------------------------------------- result = client.service.add(a=num1,b=num2) #print result if result[0] == 200: return (True, result[1]) else: return (False, result[1]) except Exception as e: return (False, e) if __name__ == '__main__': #get_software a= call_api_test(2,3) print (json.loads(a[1]))
2、調用Json格式的接口
……