本文用sypne库开发soap协议的web服务;make_server 的三个参数分别是ip,端口和应用, 接口参数为自定义数据类型和数组。
1、背景
WebService与客户端之间一般使用SOAP协议传输XML数据。WebService从数据传输格式上作了限定。WebService所使用的数据均是基于XML格式的。目前标准的WebService在数据格式上主要采用SOAP协议。SOAP协议实际上就是一种基于XML编码规范的文本协议。
1,WebService是两个系统的远程调用,使两个系统进行数据交互,如应用:
天气预报服务、银行ATM取款、使用邮箱账号登录各网站等。
2,WebService之间的调用是跨语言的调用。Java、.Net、php,发送Http请求,使用的数据格式是XML格式。
3,webxml.com.cn上面有一些免费的WebService服务,可以进去看看。
2 、应用基础
(1),理解服务:
现在的应用程序变得越来越复杂,甚至只靠单一的应用程序无法完成全部的工作。更别说只使用一种语言了。因此需要访问别人写的服务,以获得感兴趣的数据。
在写应用程序查询数据库时,并没有考虑过为什么可以将查询结果返回给上层的应用程序,甚至认为,这就是数据库应该做的,其实不然,这是数据库通过TCP/IP协议与另一个应用程序进行交流的结果,而上层是什么样的应用程序,是用什么语言,数据库本身并不知道,它只知道接收到了一份协议,这就是SQL92查询标准协议。
目前的云计算、云查杀都是一种服务,现在比较流行的说法是SOA(面向服务的框架)。
既然数据库可以依据某些标准对外部其他应用程序提供服务、而且不关心对方使用什么语言,那我们为什么就不能实现跨平台、跨语言的服务呢?
学习WebService可以将你的服务(一段代码)发布到互联网上让别人去调用,也可以调用别人机器上发布的WebService,就像使用自己的代码一样。
(2),基础概念:XML
XML Extensible Markup Language -扩展性标记语言
XML,用于传输格式化的数据,是Web服务的基础。
namespace-命名空间。
(3),基础概念:WSDL
WSDL – WebService Description Language – Web服务描述语言。
通过XML形式说明服务在什么地方-地址。address location
通过XML形式说明服务提供什么样的方法 – 如何调用。operation
(4),基础概念:SOAP
SOAP-Simple Object Access Protocol(简单对象访问协议)
SOAP作为一个基于XML语言的协议用于网上传输数据。
SOAP = 在HTTP的基础上 XML数据。
SOAP是基于HTTP的。
SOAP的组成如下:
Envelope – 必须的部分。以XML的根元素出现。
Headers – 可选的。
Body – 必须的。在body部分,包含要执行的服务器的方法。和发送到服务器的数据。
传递的数据格式:
<Envelope>
<Header></Header>
<Body>
<方法名>
方法参数
</方法名>
</Body>
</Envelope>
3 、源码实例
服务端源码
代码语言:javascript复制from spyne import Application, rpc, ServiceBase, Iterable, Integer, Unicode, String
# 如果支持soap的协议需要用到Soap11
from spyne.protocol.soap import Soap11
# 可以创建一个wsgi服务器,做测试用
from spyne.server.wsgi import WsgiApplication
class HelloWorldService1(ServiceBase):
# 输入和输出的类型,这里返回值是stringArray
@rpc(Unicode, Integer, _returns=Iterable(Unicode))
def say_hello1(ctx, 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 the completed array
"""
# 写你的服务端对应的操作
for i in range(times):
yield u'say_hello1 : Hello, %s' % name
@rpc(Unicode, Integer, _returns=Iterable(Unicode))
def test1(ctx, 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 the completed array
"""
return [u'test1 : hello, %s - %d' % (name, i) for i in range(times)]
class HelloWorldService2(ServiceBase):
@rpc(Unicode, Integer, _returns=Iterable(Unicode))
def say_hello2(ctx, 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 the completed array
"""
for i in range(times):
yield u'say_hello2 : Hello, %s' % name
@rpc(Unicode, Integer, _returns=Iterable(Unicode))
def test2(ctx, 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 the completed array
"""
return [u'test2 : hello, %s - %d' % (name, i) for i in range(times)]
application = Application([HelloWorldService1, HelloWorldService2], 'http://schemas.xmlsoap.org/soap/envelope',
in_protocol=Soap11(validator='lxml'), out_protocol=Soap11())
wsgi_application = WsgiApplication(application)
if __name__ == '__main__':
import logging
# wsgiref是python内置的一个简单的、遵循wsgi接口的服务器。
from wsgiref.simple_server import make_server
logging.basicConfig(level=logging.DEBUG)
logging.getLogger('spyne.protocol.xml').setLevel(logging.DEBUG)
logging.info("listening to http://127.0.0.1:8080")
logging.info("wsdl is at: http://127.0.0.1:8080/?wsdl")
# 127.0.0.1改成你的IP,让客户端所在电脑能访问就行
server = make_server('127.0.0.1', 8080, wsgi_application)
server.serve_forever()
客户端测试
代码语言:javascript复制pip install suds_jurko
# 基于suds_jurko做webservice客户端
from suds.client import Client
if __name__ == '__main__':
url = 'http://127.0.0.1:8080/?wsdl'
client = Client(url)
print(client)
print('-'*20)
print(client.service.say_hello1('张三', 5))
print(client.service.say_hello2('李四', 5))
print(client.service.test1('测试1', 3))
a = client.service.test2('测试2', 3)
print(a)
print(a[0])
print(a[0][0])
用webservice发布应用,如果某一时间并发量很大,无法全部进行处理,如何处理使其不丢失数据?
比较简单的方法就是使用队列缓存,然后从队列当中取数据进行处理。
1是减少客户端无用的请求 建立数据缓存,增量更新等机制尽量减少客户端的请求。
2.提前准备数据,减少实时的数据处理。 对一些请求较频繁的接口,提前处理好数据,减少cpu实时运算
3.缓存数据到redis或者memcached中,减少硬盘读写时间,提高响应速度。
所有的请求都放入一个pool里去,至于这个pool这么实现,有很多方法cache等都可以,然后建立高低水位线,去从这些pool里去取数据来处理就可以了。