python nodejs web_WebService开发: 服务端[Python] + 客户端[python & nodejs]

WebService是什么

WebService是一种跨编程语言和跨操作系统平台的远程调用技术。

跨编程语言:就是说服务端程序采用python编写,客户端程序则可以采用其他编程语言编写(nodejs、java等);

跨操作系统平台:就是说服务端程序和客户端程序可以在不同的操作系统上运行;

远程调用:就是一台计算机A上的程序可以调用另一台计算机B上一个对象的方法。eg: 银联提供给商场的pos刷卡系统、天气预报系统等;

SOAP协议是什么

WebService通过http协议发送请求和接收结果时,发送的请求内容和结果内容都是采用XML格式封装的,并增加一些特定的HTTP消息头以声明HTTP消息的内容格式。这些特定的HTTP消息头和XML内容格式就是SOAP协议。

简而言之,SOAP协议 = HTTP协议 + XML数据格式

WSDL是什么

好比我们去商店买东西,首先要知道商店里有什么东西可买,然后再来购买,商家的做法就是张贴广告海报。 WebService也一样,WebService客户端要调用一个WebService服务,首先要有知道这个服务的地址在哪,以及这个服务里有什么方 法可以调用,所以,WebService务器端首先要通过一个WSDL文件来说明自己家里有啥服务可以对外调用,服务是什么(服务中有哪些方法,方法接受 的参数是什么,返回值是什么),服务的网络地址用哪个url地址表示,服务通过什么方式来调用。

WSDL(Web Services Description Language)就是这样一个基于XML的语言,用于描述Web Service及其函数、参数和返回值。它是WebService客户端和服务器端都 能理解的标准格式。因为是基于XML的,所以WSDL既是机器可阅读的,又是人可阅读的,这将是一个很大的好处。一些最新的开发工具既能根据你的 Web service生成WSDL文档,又能导入WSDL文档,生成调用相应WebService的代理类代码。

WSDL 文件保存在Web服务器上,通过一个url地址就可以访问到它。客户端要调用一个WebService服务之前,要知道该服务的WSDL文件的地址。 WebService服务提供商可以通过两种方式来暴露它的WSDL文件地址:1.注册到UDDI服务器,以便被人查找;2.直接告诉给客户端调用者。

WebService开发

1.服务端开发(基于python—spyne库)

#!/usr/bin/env python

# -*- coding: utf-8 -*-

"""

server.py

~~~~~~~~~~~~~~~~~~~~~~~

Description of this file

:author: nut

:copyright: (c) 2020, Comcat

:date created: 2020-12-02

:python version: 3.5

"""

# Application is the glue between one or more service definitions, interface and protocol choices.

from spyne.application import Application

# @rpc 修饰器将方法公开为远程过程调用,并声明其接收和返回的数据类型

from spyne.decorator import rpc

# spyne.service.ServiceBase是所有服务定义的基类

from spyne import ServiceBase

# 数据类型

from spyne import Integer, Unicode, Array, ComplexModel, Iterable, String

# soap1.1标准

from spyne.protocol.soap import Soap11

# 我们的服务是通过http进行传输的,WsgiApplication将包装Application实例

from spyne.server.wsgi import WsgiApplication

# python内置的wsgi服务器模块:wsgiref,用于创建wsgi服务

from wsgiref.simple_server import make_server

# step1: 自定义数据结构

class Person(ComplexModel):

name = Unicode

age = Integer

class PeopleResponse(ComplexModel):

name = Person

message = Unicode

# step2: 定义服务

class HelloWorldService(ServiceBase):

@rpc(Unicode, Integer, _returns=Iterable(Unicode))

def say_hello(self, name, times):

for i in range(times):

yield "Hello %s, It's the %s time to meet you." % (name, i + 1)

@rpc(Array(Person), _returns=Iterable(Unicode))

def say_hello_1(self, persons):

print('-------say_hello_1()--------')

if not persons:

yield 'None'

for person in persons:

print('name is : %s, age is %s.' % (person.name, person.age))

yield 'name is : %s, age is %s.' % (person.name, person.age)

class HelloWorldService2(ServiceBase):

@rpc(Array(String), _returns=Iterable(Unicode))

def say_hello_2(self, persons):

if not persons:

yield 'None'

for person in persons:

yield person

@rpc(Person, _returns=PeopleResponse)

def say_hello_3(self, person):

if not person:

return {}

else:

# return PeopleResponse(name=People(**person))

return {

"name": person,

"message": 'name is : %s, age is %s.' % (person.name, person.age)

}

# step3:

application = Application([HelloWorldService, HelloWorldService2],

'spyne.examples.hello',

in_protocol=Soap11(validator='lxml'),

out_protocol=Soap11())

# step4:

wsgi_application = WsgiApplication(application)

if __name__ == '__main__':

import logging

host = '127.0.0.1'

port = 8902

logging.basicConfig(level=logging.DEBUG)

# 指定日志记录器的名称,设置日志记录级别

logging.getLogger('spyne.protocol.xml').setLevel(logging.DEBUG)

logging.info("listening to http://127.0.0.1:8902")

logging.info("wsdl is at: http://localhost:8902/?wsdl")

# step5: 创建wsgi服务

server = make_server(host, port, wsgi_application)

server.serve_forever()

2. 客户端开发(Python & Nodejs)

suds - Python client

需安装python第三方库suds:pip install suds-py3

#!/usr/bin/env python

# -*- coding: utf-8 -*-

"""

client_requests_suds.py

~~~~~~~~~~~~~~~~~~~~~~~

模拟客户端请求——suds版本

:author: nut

:copyright: (c) 2020, Comcat

:date created: 2020-12-01

:python version: 3.7

"""

from suds.client import Client

host = '127.0.0.1'

port = 8902

client = Client('http://%s:%s/?wsdl' % (host, port))

# print(client) # 打印wsdl内容

# print('=' * 20)

persons = client.service.say_hello('zhangsan', 2)

print(persons)

print('-' * 20)

person = {}

person['name'] = 'zhangsan'

person['age'] = 23

persons = client.factory.create('PersonArray')

persons.Person.append(person)

persons.Person.append(person)

person = client.service.say_hello_1(persons)

print(person)

print('=' * 20)

persons = client.factory.create('stringArray')

persons.string.append('lisi')

persons.string.append('zhangsan')

person = client.service.say_hello_2(persons)

print(person)

print('=' * 20)

pers = {"name": u"张三", "age": 23}

result = client.service.say_hello_3(pers)

print(result)

zeep - Python client

需安装python第三方库zeep:pip install zeep

#!/usr/bin/env python

# -*- coding: utf-8 -*-

"""

client_requests_zeep.py

~~~~~~~~~~~~~~~~~~~~~~~

模拟客户端请求——zeep版本

:author: nut

:copyright: (c) 2020, Comcat

:date created: 2020-12-02

:python version: 3.5

"""

from zeep import Client

ip = '127.0.0.1'

port = 8901

client = Client("http://%s:%s/?wsdl" % (ip, port))

# print(client.wsdl.dump()) # 解析wsdl

# print('=' * 20)

### say_hello

r = client.service.say_hello('zhansgan', 3)

print(r)

print('-' * 20)

### say_hello_1

factory = client.type_factory("ns0")

person = factory.Person(name='zhangsan', age=23)

persons = factory.PersonArray([person, person])

r = client.service.say_hello_1(persons)

print(r)

print('-' * 20)

### say_hello_2

factory = client.type_factory("ns0")

persons = factory.stringArray(["zhansgan", "lisi"])

r = client.service.say_hello_2(persons)

print(r)

print('-' * 20)

### say_hello_3

# factory = client.type_factory("ns0")

person = {"name": u"张三", "age": 23}

r = client.service.say_hello_3(person)

print(r)

- node client (亲测可用)

需安装node第三方库strong-soap:npm install strong-soap

var soap = require("strong-soap").soap;

var ip = '127.0.0.1';

var port = 8901;

var WSDL_URL = "http://" + ip + ":" + port + "/?wsdl";

soap.createClient(WSDL_URL, {}, function (err, client) {

client.setEndpoint(WSDL_URL)

// console.log(client)

// console.log("===============================================")

// console.log(client.describe())

// console.log("===============================================")

// 调用say_hello方法 (亲测可行)

client.say_hello({"name": "ccc", "times": 2}, function (err, result) {

console.log("Err: ")

console.log(err)

console.log("Result: ")

console.log(result)

console.log("===============================================")

})

// say_hello_1 参数结构

let arg_1 = {

"persons": {

"Person": [{"name": "zzz", "age": 23}, {"name": "aaa", "age": 18}

]

}

}

// 调用say_hello_1方法 (传参可行)

client.say_hello_1(arg_1, function (err, result) {

console.log("Err: ")

console.log(err)

console.log("Result: ")

console.log(result)

console.log("===============================================")

})

// say_hello_2 参数结构

let arg_2 = {

persons: {

string: ["aaa", "zzz"]

}

}

// 调用say_hello_2方法 (传参可行)

client.say_hello_2(arg_2, function (err, result) {

console.log("Err: ")

console.log(err)

console.log("Result: ")

console.log(result)

console.log("===============================================")

})

// say_hello_3 参数结构

let arg_3 = {

person: {

name: "aaa",

age: 24

}

}

// 调用say_hello_3方法 (传参可行)

client.say_hello_3(arg_3, function (err, result) {

console.log("Err: ")

console.log(err)

console.log("Result: ")

console.log(result)

console.log("===============================================")

})

})

node:strong-soap开发客户端,难点在于: complexType参数的构造。

上述node客户端脚本执行结果如下:

# 结果:

Err:

null

Result:

{ say_helloResult:

{ string:

[ 'Hello ccc, It\'s the 1 time to meet you.',

'Hello ccc, It\'s the 2 time to meet you.' ] } }

===============================================

Err:

null

Result:

{ say_hello_1Result:

{ string: [ 'name is : zzz, age is 23.', 'name is : aaa, age is 18.' ] } }

===============================================

Err:

null

Result:

{ say_hello_2Result: { string: [ 'aaa', 'zzz' ] } }

===============================================

Err:

null

Result:

{ say_hello_3Result:

{ name: { name: 'aaa', age: 24 },

message: 'name is : aaa, age is 24.' } }

===============================================

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值