面向服务的架构 (SOA) 在当今的业务战略中具有至关重要的作用。混搭企业组件已成为所有任务关键的企业应用程序的标准要求,从而确保在企业架构的各层实现顺畅的服务编排。对此,Python 是一个不错的选择,我们可以通过这一工具使用一个免费提供的开源库快速地将这些服务连接在一起。

对于 Python 来说,处理 Web 服务描述语言 (WSDL)、简单对象访问协议 (SOAP) 或表示状态传输 (REST) 就如同使用语言固有的内置特性一样顺畅。最近几年出现了许多使用 Web 服务的模块,这让 Python 在 SOA 领域可与 Java EE 或 .NET 等大型编程体系分庭抗争。

在本部分中,我们将探讨如何通过一个名为 suds 的使用 SOAP 的新库来处理 SOAP 和 REST 通信,如何只使用标准库来部署一个符合 WSGI 的简单 Web 服务,并了解 Oracle Application Express 如何轻松地与 Python 通信。

使用 SOAP

过去,人们编写了许多 Python 模块来处理 SOAP 通信,这些模块包括 ZSI、SOAPpy 和 soaplib。不过在本教程中,我们将使用一个新的名为 suds 的轻型库。这个库旨在高效地使用 Web 服务,它提供了一种轻松使用 WSDL 端点的方法。

一切均从一个发出底层 Web 服务调用的 Client 对象的实例化开始。随后,suds 对响应进行处理,产生一个纯 XML 格式或经过解析的 Python 对象表示。返回对象的类型取决于服务的定义,并由 suds 自动转换。

在此我们将访问两种不同的 Web 服务:一个将返回纯 XML 响应,另一个将返回经过解析的表示。现在我们就来看看 Oracle Corporation(纳斯达克代号:ORCL)是如何做的。

清单 1. orcl_quote.py:通过 WSDL 端点访问 Oracle 的股票信息。
import suds
from xml.etree import ElementTree

quote_ws = suds.client.Client("http://www.webservicex.net/stockquote.asmx?WSDL")
orcl_quote_resp = quote_ws.service.GetQuote("ORCL")
orcl_quote_xml = ElementTree.fromstring(orcl_quote_resp)
orcl_last = orcl_quote_xml.findtext("Stock/Last")
orcl_datetime = orcl_quote_xml.findtext("Stock/Date") + "@" + orcl_quote_xml.findtext("Stock/Time")
print "ORCL stock value = %s at %s" % (orcl_last, orcl_datetime

如果设置了防火墙,则将第一行代码更改为如下内容,使用相应的代理名称和端口进行替换:

quote_ws = suds.client.Client("http://www.webservicex.net/stockquote.asmx?WSDL",
     proxy = dict(http = “http://myproxy:myproxyport”))

结果是,我们获得类似如下的输出:

[oracle@xe ~]$ python orcl_quote.py
ORCL stock value = 32.96 at 11/15/2011@4:00pm

如果我们仔细查看响应对象,就会发现 suds 在后台使用了 Python 的 SAX XML 库来提供对接收的 XML 对象的表示。

>>> type(orcl_quote_resp)
<class 'suds.sax.text.Text'>
>>> print orcl_quote_resp
<StockQuotes><Stock><Symbol>ORCL</Symbol><Last>32.96</Last><Date>11/15/2011</Date><Time>4:00pm</Time><Change>0.00</Change><Open>N/A</Open><High>N/A</High><Low>N/A</Low><Volume>0</Volume><MktCap>166.3B</MktCap><PreviousClose>32.96</PreviousClose><PercentageChange>0.00%</PercentageChange><AnnRange>24.72 - 36.50</AnnRange><Earns>1.758</Earns><P-E>18.75</P-E><Name>Oracle Corporatio</Name></Stock></StockQuotes>

此时就需要 xml.ElementTree 的帮助了,它让我们能轻松地以 orcl_quote_xml.findtext(“Stock/Last”) 调用的形式使用 findtext() 方法提取所需信息。

如果我们要获取 SOAP 响应本身,则情况稍有变化。suds 透明地将该响应转换为 Python 对象。

清单 2. redwood.py 检查 Oracle 总部当前的天气状况
import suds
weather_ws = suds.client.Client("http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL")
redwood = weather_ws.service.GetCityWeatherByZIP("94065")
print redwood

作为结果,此脚本以格式化的字符串表示形式返回一个 Python 对象,如下所示:

[oracle@xe ~]$ python redwood.py
(WeatherReturn){
   Success = True
   ResponseText = "City Found"
   State = "CA"
   City = "Redwood City"
   WeatherStationCity = "Hayward"
   WeatherID = 11
   Description = "Clear"
   Temperature = "N/A"
   RelativeHumidity = "N/A"
   Wind = "NE5"
   Pressure = "30.17S"
   Visibility = None
   WindChill = None
   Remarks = None
 }

仔细观察该对象,我们发现 redwood 变量下现在是一个 Python 对象实例,该对象实例有一些可访问的属性,如上面的字符串表示形式所示。这意味着我们现在可以引用 redwood.Pressure 或 redwood.Wind,并分别获得类似于 30.17S 或 NE5 的结果。

所有可用服务及其端口连同其绑定和方法的文本表示形式都通过 client.wsdl.service 属性公开:

>>> weather_ws.wsdl.services
[(Service){
   name = "Weather"
   qname = "(Weather, http://ws.cdyne.com/WeatherWS/)"
   ports[] =
       (Port){
       name = "WeatherSoap"
       qname = "(WeatherSoap, http://ws.cdyne.com/WeatherWS/)"
       _Port__service = (Service)...
       binding =
              (Binding){
              name = "WeatherSoap"
              qname = "(WeatherSoap, http://ws.cdyne.com/WeatherWS/)"
              operations =
              {
                      GetCityForecastByZIP =
                      (Operation){
                             name = "GetCityForecastByZIP"
                             soap =
...

suds 模块本身能够通过 suds.factory 命名空间处理复杂的类型,并且可以处理多个 WSDL 端口、SOAP 请求中的自定义头、HTTP 身份验证和 WS-security 的子集。

现在说说 REST

现在无处不在的另一种 Web 服务标准是表示状态传输 (REST)。REST 的开销远低于 WSDL 和 SOAP,其工作方式如同用户与互联网资源交互的方式,可访问统一资源定位器 (URL) 和统一资源标识符 (URI) 来获得所需的资源内容。

要使用 REST,您不需要外部库或专用框架;Python 语言库内部的模块足以满足您的所有 REST 功能需求。要快速查看 Oracle Corporation 内部发生的情况,我们只需查看其 Twitter 信源。有了 Python,其实现非常简单。请参见清单 3 了解最新状态检查的基本代码。

清单 3. twitter.py:查看给定用户的 Twitter 状态信源
import json
import urllib2
import sys

twitter_api = "https://api.twitter.com/1/statuses/user_timeline.json?screen_name=%s&count=5"
endpoint = urllib2.urlopen(twitter_api % sys.argv[1])
tweets = json.loads(endpoint.read())

for tweet in tweets:
  print "%s\n%s\n" % (tweet["created_at"], tweet["text"])

如果设置了防火墙,则在该脚本的开头插入如下所示的一行,使用相应的代理名称和端口进行替换:

urllib2.install_opener(urllib2.build_opener(urllib2.ProxyHandler({'https':'myproxy:myproxyport'})))

运行 twitter.py 将输出五条最新微博及其发布日期:

[oracle@xe ~]$ python twitter.py Oracle
Tue Nov 15 20:30:09 +0000 2011
Have a need for speed? Find out why #Oracle #Exalogic Elastic #Cloud puts your enterprise on the fast track: http://t.co/AE5btu15

Tue Nov 15 16:00:09 +0000 2011
Webcast today at 1pm ET: Storage Strategies for Accelerating Database Test & Development: Register @ http://t.co/7WKGVXB4

Mon Nov 14 21:45:12 +0000 2011
Register now for 11/17 Webcast: Privileged User Access Control with #Oracle Database 11g. Details @ http://t.co/QCcwxJvk

Mon Nov 14 20:00:42 +0000 2011
Are your customers loyal? Would you like them to be? Join us for our upcoming Webcast 11/17. Register @ http://t.co/48ZNUSCS

Mon Nov 14 16:00:56 +0000 2011
Storage Strategies for Accelerating Database Test & Development:Increase the speed, efficiency of test environment http://t.co/AtxrD8aT

现在,正如使用 Web 服务所经历的那样,我们转到更复杂的部分,这里我们在 Oracle Database 11g 快捷版的 HR(人力资源)模式之上提供 REST 式 API。

清单 4 中的示例除了使用我们已经非常熟悉的 cx_Oracle 模块之外,还将使用 json、urlparse 和 wsgiref 模块。这里不使用任何可用的 Web 框架,我们的目的是使用广泛采用的 Web 服务器网关接口 (WSGI) 在 Python 的标准库之上实现简单的基于 JSON 的 REST 服务。此服务会响应请求,以应用程序/json 内容类型的 JSON 表示返回完整的员工信息。wsgiref.simple_server 模块中的 make_server 过程处理端口 8001 上的 HTTP 请求,直至出现 KeyboardInterrupt 异常(按 CTRL+C 可触发该异常)。

清单 4. restserver.py:员工信息 JSON Web 服务
import json
import cx_Oracle
import urlparse
from wsgiref.simple_server import make_server

def hr_web_service(environ, start_response):
  start_response('200 OK', [('Content-Type', 'application/json')])
  resp = ""
  url = urlparse.urlparse(environ['PATH_INFO'])
  parameters = urlparse.parse_qs(environ['QUERY_STRING'])
  if url.path=="/emp":
    empid = parameters['id']
    with cx_Oracle.connect('hr/hr') as db:
      cursor = db.cursor()
      cursor.execute("select * from employees e where e.employee_id=:empid", empid)
      rows = []
      for row in cursor:
        rowdict = {}
        for pos, col in enumerate(cursor.description):
          rowdict[col[0]] = str(row[pos])
        rows += [rowdict]
    return json.dumps(rows)
  return "Invalid request."

if __name__=="__main__":
  ws = make_server('', 8001, hr_web_service)
  ws.serve_forever()

运行 restserver.py 并将浏览器定向到 http://localhost:8001/emp?id=110,将会转换有关员工 110 的 Python 字典对象并输出 JSON 编码的表示:

[{"PHONE_NUMBER": "515.123.4567", "SALARY": "24000.0", "FIRST_NAME": "Steven", "LAST_NAME": "King", "JOB_ID": "AD_PRES", "HIRE_DATE": "2003-06-17 00:00:00", "COMMISSION_PCT": "None", "EMPLOYEE_ID": "100", "MANAGER_ID": "None", "EMAIL": "SKING", "DEPARTMENT_ID":"90"}]

REST 式 API 远比相应的 SOAP API 轻便,时至今日,REST 式 API 代表了在企业和互联网环境中使用和提供 Web 服务的主要趋势。REST 自身依赖 HTTP,从而将焦点从有效载荷类型转为仅端点。SOAP 和 WSDL 尽管功能极其强大,但会带来大量开销,并且使用起来更复杂。无论您选择哪一个,Python 都允许以“Python 式”方式轻松地工作 — 一致、高效、代码很少。

响应 Oracle Application Express 调用

Oracle Application Express 4.0 支持 REST 式 Web 服务和 SOAP Web 服务。了解此功能之后,我们可以利用另一种基于 Application Express-WSGI 桥的 Oracle-Python 模式。

我们来利用清单 4 中的 restserver.py 提供通过 Application Express 调用的服务。如果您计划在远程位置运行 Python 服务器,则需要启用对此计算机的远程 APEX 调用。清单 5 显示了 PL/SQL 代码,它需要以 SYSDBA 身份运行启用对任何计算机的调用(就如何处理外部网络调用,您可能需要咨询网络管理员)。

清单 5. 为用户 APEX_040000 授予所有主机的连接权限

DECLARE
  ACL_PATH  VARCHAR2(4000);
  ACL_ID    RAW(16);
BEGIN

SELECT ACL INTO ACL_PATH FROM DBA_NETWORK_ACLS
   WHERE HOST = '*' AND LOWER_PORT IS NULL AND UPPER_PORT IS NULL;

SELECT SYS_OP_R2O(extractValue(P.RES, '/Resource/XMLRef')) INTO ACL_ID
    FROM XDB.XDB$ACL A, PATH_VIEW P
   WHERE extractValue(P.RES, '/Resource/XMLRef') = REF(A) AND
         EQUALS_PATH(P.RES, ACL_PATH) = 1;

DBMS_XDBZ.ValidateACL(ACL_ID);
   IF DBMS_NETWORK_ACL_ADMIN.CHECK_PRIVILEGE(ACL_PATH, 'APEX_040000', 
     'connect') IS NULL THEN 
      DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE(ACL_PATH, 'APEX_040000', TRUE, 'connect'); 
  END IF;

EXCEPTION
  WHEN NO_DATA_FOUND THEN
  DBMS_NETWORK_ACL_ADMIN.CREATE_ACL('python_apis.xml',
    'ACL - Mastering Oracle-Python, Part 7','APEX_040000', TRUE, 'connect');
  DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL('python_apis.xml','*');
END;
/

COMMIT;

(有关详细信息,请参见此 Oracle 文档。)

现在,我们登录到 APEX 工作区,并从 Application Builder 中选择 Create > Application Type:Database > From Scratch > Name:PYTHONWS (schema:HR) > Add Page (Blank) >,然后选择两次 Create。现在我们有了一个名为 PYTHONWS 的应用程序,它包含一个名为“Page 1”的空白页面。

在我们实际使用 Web 服务之前,首先需要定义对此服务的引用。为此,我们需要将浏览器指向 Application Builder > Shared Components > Web Service References > Create > REST > Name:EMPLOYEE_WEBSRV, URL:http://localhost:81/emp(或者您将运行 Python 服务的服务器)> REST Input Parameters:Add Parameter “id” of type “string” > REST Output Parameters:Output format:Text, Name:json, Path:1 > Create。此时,我们应拥有了一个有效引用,我们可以轻松通过“Test REST Web Reference”页面来验证该引用,当 APEX 内的列表视图中显示出 Web 服务引用时,可以通过 Test 列图标访问此页面。

 
图 1 通过 APEX REST Web 引用验证 restserver.py

有了正确定义的服务,我们现在可以将此功能添加到页面中。在 Page 1 上创建新区域,为此选择 Form > Form on Web Service > Web Service Reference:EMPLOYEE_WEBSRV > Page Number:1 > P1_ID > P1_JSON > Create。这些基本步骤足以为页面提供输入域 P1_ID,通过 Web 服务请求过程将来自 Web 服务的响应返回到 P1_JSON 域中。

总结

本文介绍了通过开源模块和 Python 的标准库本身使用 SOAP 和 REST Web 服务的重要事项。我们了解了如何轻松地接入 Twitter 流以及实现 Oracle Application Express 和 Python Web 服务之间的通信。Python 的动态特性和极快的开发速度再一次证明了它是用于实现 SOA 的可靠工具。 .

精通 Oracle+Python,第 7 部分:面向服务的 Python 架构的更多相关文章

  1. 面向服务的体系架构(SOA)

    面向服务的体系架构(SOA) 1.面向服务的体系架构(SOA) 面向服务的架构(service-oriented architecture)是Gartner于2O世纪9O年代中期提出的面向服务架构的概 ...

  2. SOA——面向服务的体系架构

    上一篇博文中提到了"紧耦合"的现象.怎样解决?SOA.採用面向服务的体系架构. 一.What? SOA=Service-oriented Architecture面向服务的体系结构 ...

  3. 面向服务的体系架构SOA

    面向服务的体系架构SOA 序言 在.Net的世界中,一提及SOA,大家想到的应该是Web Service,WCF,还有人或许也会在.NET MVC中的Web API上做上标记,然后泛泛其谈! 的确,微 ...

  4. 说说面向服务的体系架构SOA

    序言 在.Net的世界中,一提及SOA,大家想到的应该是Web Service,WCF,还有人或许也会在.NET MVC中的Web API上做上标记,然后泛泛其谈! 的确,微软的这些技术也确实推动着面 ...

  5. jquery 直接调用 wcf,面向服务的SOA架构 ( 第二天)

    在前面的基础上,我们来开始第二天编写 客户端 的东西,不过讲之前,我想告诉大家的是: 这个简单的SOA的架构,我们直接通过wcf 调用到 后台的方法, 而中间没有使用 C#代码,大大减少我们客户端的代 ...

  6. 分布式架构设计(一) --- 面向服务的体系架构 SOA

    1.1 基于TCP协议的RPC 1.1.1 RPC名词解释 RPC的全称是Remote Process Call,即远程过程调用,RPC的实现包括客户端和服务端,即服务调用方和服务提供方.服务调用方发 ...

  7. 面向服务的体系架构 SOA(二) --- 服务的路由和负载均衡

    2. 服务的路由和负载均衡 1.2.1 服务化的演变 SOA设计思想:分布式应用架构体系对于业务逻辑复用的需求十分强烈,上层业务都想借用已有的底层服务来快速搭建更多.更丰富的应用,降低新业务开展的人力 ...

  8. 面向服务的体系架构 SOA(三) --- Zookeeper API、zkClient API的使用

    zookeeper简单介绍及API使用 1.1 zookeeper简介 zookeeper是一个针对大型分布式系统的可靠的协调系统,提供的功能包括配置维护.名字服务.分布式同步.组服务等.zookee ...

  9. 大型分布式架构设计与实现-第一章SOA(面向服务的体系架构)

    拜读了大型分布式架构设计与实现,觉得该书作为入门不错,但内容过于简单,描述过于琐碎,小节之间连续性不强,不适合深入钻研学习.但为了更多的希望向架构师行业靠拢的工程师学习需要,本博客将对上书进行简化讲解 ...

随机推荐

  1. jmeter控制器

    1.仅一次控制器  这个控制器可以保证线程在多次循环跑得情况下只登陆一次 2.循环控制器(Loop Controller:设置循环次数 结果: 3. ForEach控制器(ForEach Contro ...

  2. return 和 exit

    此篇文不会阐述具体的原理,而是只记录实际应用如何避免一些问题 在<C语言程序设计-现代方法>第9.5章节中有这样一段说明, return语句和exit函数之间的差异是:不管哪个函数调用ex ...

  3. IO 流—>>>补充

    流操作规律: 示例:1. 源: 键盘录入 目的: 控制台 2.源:文件 目的:控制台 3.源: 键盘录入 目的: 文件 基本规律: 面对流对象很多,不知道用哪一个的时候: 通过两个明确来完成 1.明确 ...

  4. phpstudy配置虚拟主机

    配置 phpstudy 虚拟主机 1在httpd.conf中  把#Include conf/extra/httpd-vhosts.conf前面的#去掉 2在站点域名管理 添加 要配置的 虚拟主机 添 ...

  5. SDK更新太慢

    同时,更新ADT和SDK Manager 在SDK Manager下Tools->Options打开了SDK Manager的Settings,选中“Force https://… source ...

  6. SOA体系结构基础培训教程-规范标准篇

    引子:本文是<SOA体系结构基础培训教程>第3章<SOA标准与规范>课件,版权所有,转载请注明出处. 随着SOA在业界的应用日益广泛,SOA的标准化问题也成为各界日益关注的焦点 ...

  7. Excel中如何查找并列出所有链接(外部数据链接)?

    在 Excel 中,有时会需要创建外部链接来引用其他工作簿的单元格内容,但是如果想要找出所有链接并且还要将这些外部数据链接列在一个工作簿当中是有点难度的.下面我会介绍一些快捷方法,不仅能够快速帮你找出 ...

  8. Android仿微信UI布局视图(圆角布局的实现)

    圆角button.或布局能够在xml文件里实现,但也能够使用图片直接达到所需的效果,曾经版本号的微信就使用了这样的方法. 实现效果图:    watermark/2/text/aHR0cDovL2Js ...

  9. 【转】关于C#接口和抽象类的一些说明

    接口和抽象类 1.概念 什么是接口? 接口是包含一组虚方法的抽象类型,其中每一种方法都有其名称.参数和返回值. 接口方法不能包含任何实现,CLR允许接口可以包含事件.属性.索引器. 一个类可以实现多个 ...

  10. IE浏览器div错乱问题

    这个问题属于各浏览器的兼容问题,有时候在其他浏览器中,html页面布局都是正常显示,唯独IE浏览器的div块布局错乱了,可能是html文件上面的报头标准出现错误. 就是一段报头,告诉浏览器,你的文档以 ...