Ruby Web 服务
Ruby Web 服务 - SOAP (遗留方法)
Section titled “Ruby Web 服务 - SOAP (遗留方法)”什么是 SOAP?
Section titled “什么是 SOAP?”简单对象访问协议 (SOAP) 是一种基于 XML 的消息协议,用于在 Web 服务的实现中交换结构化信息。它依赖 XML 作为其消息格式,通常使用 HTTP 或 SMTP 进行消息协商和传输。SOAP 在过去更普遍,但由于简单性和更低的开销,在新开发中已很大程度上被使用 JSON 的 RESTful API 取代。
本教程涵盖 SOAP4R,这是 Ruby 的一个历史上的 SOAP 实现。虽然 SOAP 和 SOAP4R 在今天的新项目不常用,但理解它们对于与现有遗留系统交互可能有用。对于 Ruby 中的现代 Web 服务开发,考虑使用像 HTTParty、Faraday 这样的库来消费(调用)REST/JSON API,以及 Ruby on Rails (API 模式)、Sinatra 或 Grape 这样的框架来构建它们。
SOAP4R 及其后继者 soap4r-ng
Section titled “SOAP4R 及其后继者 soap4r-ng”SOAP4R 是用于 Ruby 的原始 SOAP 库。它不再积极维护。一个社区维护的分支 (fork),soap4r-ng (SOAP for Ruby - Next Generation),旨在提供持续支持并与较新版本 Ruby 兼容。如果您必须在 Ruby 中使用 SOAP,soap4r-ng 是推荐的选择,而非原始的 SOAP4R。
安装 soap4r-ng:
您可以使用 RubyGems 安装 soap4r-ng:
$ gem install soap4r-ng此命令将安装 soap4r-ng 及其依赖项。
使用 soap4r-ng 编写 SOAP 服务器
Section titled “使用 soap4r-ng 编写 SOAP 服务器”soap4r-ng 支持构建独立的 SOAP 服务器。过程包括以下关键步骤:
步骤 1: 继承自 SOAP::RPC::StandaloneServer
Section titled “步骤 1: 继承自 SOAP::RPC::StandaloneServer”创建一个继承自 SOAP::RPC::StandaloneServer 的新类。
require 'soap/rpc/standaloneserver'
class MySOAPServer < SOAP::RPC::StandaloneServer # ... 服务器逻辑 ...end步骤 2: 定义服务方法
Section titled “步骤 2: 定义服务方法”这些是您的服务器类中的常规 Ruby 方法,它们将作为 Web 服务操作暴露出来。
class MySOAPServer < SOAP::RPC::StandaloneServer # ... (此处为 initialize 方法)
# 服务方法 def add(a, b) return a + b end
def divide(a, b) raise SOAP::FaultError, "Division by zero" if b == 0 return a.to_f / b endend步骤 3: 在 initialize 方法中暴露方法
Section titled “步骤 3: 在 initialize 方法中暴露方法”在您的服务器类的 initialize 方法中,使用 add_method 来声明哪些方法是 SOAP 服务的一部分,并指定它们的名称和参数签名。
class MySOAPServer < SOAP::RPC::StandaloneServer def initialize(*args) super # 调用父类 initialize 方法至关重要 # add_method(接收者, soap_方法名, *参数名列表_字符串形式) add_method(self, 'add', 'a', 'b') add_method(self, 'divide', 'a', 'b')
# 对于更复杂的参数类型 (in, out, inout): # add_method(self, 'complex_method', ['in', 'param1'], ['out', 'param2_out'], ['inout', 'param3_inout']) end # ... 服务方法 (add, divide) ...end步骤 4: 启动服务器
Section titled “步骤 4: 启动服务器”实例化您的服务器类并调用其 start 方法。您需要提供应用名称、命名空间 URI、主机名和端口。
# 承接上文# server = MySOAPServer.new('MyCalculatorApp', 'urn:ruby:calculator', 'localhost', 8080)# trap('INT') { server.shutdown }完整的服务器示例:
#!/usr/bin/env rubyrequire 'soap/rpc/standaloneserver'
class MySOAPServer < SOAP::RPC::StandaloneServer def initialize(*args) super # 调用父类 initialize 方法 add_method(self, 'add', 'a', 'b') add_method(self, 'divide', 'a', 'b') end
def add(a, b) return a.to_f + b.to_f end
def divide(a, b) if b.to_f == 0 raise SOAP::FaultError, "Cannot divide by zero." end return a.to_f / b.to_f endend
begin server_host = 'localhost' server_port = 8080 server = MySOAPServer.new('CalculatorService', # 应用名称 'urn:ruby:calculator', # 命名空间 server_host, # 主机 server_port) # 端口
puts "正在启动 SOAP 服务器于 #{server_host}:#{server_port}..." # 按 Ctrl+C 优雅关闭 trap('INT') do puts "\n正在关闭 SOAP 服务器..." server.shutdown end
server.startrescue StandardError => err puts "启动服务器出错: #{err.message}" puts err.backtrace.join("\n")end要运行此服务器,将其保存为 soap_server.rb 并执行 ruby soap_server.rb。它将监听 http://localhost:8080。
使用 soap4r-ng 编写 SOAP 客户端
Section titled “使用 soap4r-ng 编写 SOAP 客户端”使用 SOAP::RPC::Driver 类来创建 SOAP 客户端。您需要服务器的端点 URL 以及服务方法的命名空间。
步骤 1: 创建一个 SOAP::RPC::Driver 实例
Section titled “步骤 1: 创建一个 SOAP::RPC::Driver 实例”使用端点 URL 和命名空间实例化 SOAP::RPC::Driver。
require 'soap/rpc/driver'
ENDPOINT_URL = 'http://localhost:8080/' # 您的 SOAP 服务器正在运行的地方NAMESPACE = 'urn:ruby:calculator' # 服务器中定义的命名空间
driver = SOAP::RPC::Driver.new(ENDPOINT_URL, NAMESPACE)步骤 2: 将服务方法添加到驱动器
Section titled “步骤 2: 将服务方法添加到驱动器”在驱动器实例上使用 add_method 方法来定义您想要调用的远程方法,以及它们的参数名称。
# driver.add_method('远程方法名', '参数1名', '参数2名', ...)driver.add_method('add', 'a', 'b')driver.add_method('divide', 'a', 'b')步骤 3: 调用远程方法
Section titled “步骤 3: 调用远程方法”在驱动器对象上调用方法,就好像它们是本地方法一样。
# 结果 = driver.远程方法名(值1, 值2, ...)完整的客户端示例:
#!/usr/bin/env rubyrequire 'soap/rpc/driver'
ENDPOINT_URL = 'http://localhost:8080/'NAMESPACE = 'urn:ruby:calculator'
begin driver = SOAP::RPC::Driver.new(ENDPOINT_URL, NAMESPACE)
# 可选:启用详细的通信日志用于调试 # driver.wiredump_dev = STDERR # 或 STDOUT,或一个文件
driver.add_method('add', 'a', 'b') driver.add_method('divide', 'a', 'b')
# 调用远程方法 sum_result = driver.add(25, 17) puts "25 + 17 = #{sum_result}"
quotient_result = driver.divide(100, 4) puts "100 / 4 = #{quotient_result}"
# 调用可能抛出 SOAP Fault 的方法的示例 begin error_result = driver.divide(10, 0) puts "10 / 0 = #{error_result}" # 这行代码不会被执行到 rescue SOAP::FaultError => e puts "发生了 SOAP Fault: #{e.message}" puts "故障码: #{e.faultcode}" puts "故障字符串: #{e.faultstring}" end
rescue StandardError => err puts "客户端错误: #{err.message}" puts err.backtrace.join("\n")end要运行此客户端(请确保 soap_server.rb 首先正在运行),将其保存为 soap_client.rb 并执行 ruby soap_client.rb。
预期输出:
25 + 17 = 42.0100 / 4 = 25.0SOAP Fault occurred: SOAP Fault: Cannot divide by zero.Fault Code: ServerFault String: Cannot divide by zero.进一步考虑:
Section titled “进一步考虑:”- WSDL2Ruby:
soap4r-ng(以及原始的 SOAP4R) 通常包含一个名为wsdl2ruby.rb的工具,该工具可以从 WSDL (Web 服务描述语言) 文件生成客户端存根代码。如果 WSDL 可用,这可以简化客户端开发。 - **错误处理:**准备好处理
SOAP::FaultError(用于处理 SOAP 服务返回的错误)以及标准网络错误。 - **复杂性:**与 REST 相比,SOAP 涉及更复杂的 XML 消息和状态管理。调试有时可能具有挑战性;在客户端驱动器上启用
wiredump_dev可能有帮助,通过显示交换的原始 XML 消息。
虽然本教程提供了 SOAP4R (通过 soap4r-ng) 的基本概述,但请记住,行业已很大程度上转向使用 JSON 的 REST API,以获得简单性、性能和易用性。SOAP 知识的主要价值在于维护或集成现有的遗留系统。