使用Sinatra创建Soap Web Service

简单对象访问协议(SOAP)是一种轻量的、简单的、基于 XML 的协议,它被设计成在 WEB 上交换结构化的和固化的信息。 SOAP 可以和现存的许多因特网协议和格式结合使用,包括超文本传输协议( HTTP),简单邮件传输协议(SMTP),多用途网际邮件扩充协议(MIME)。它还支持从消息系统到远程过程调用(RPC)等大量的应用程序。

本文中得示例是Soap与Http结合的Web service。其实现了一个简单的Echo和Reverse Echo的服务,既请求原文返回和请求倒序返回。就纯技术层面来说,本质上就是post 一个制造xml格式的请求,获得一个xml格式的response的Http Request。

首先,使用xsd明确request和response的xml结构

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://www.xianlinbox.net/echo" xmlns="http://www.xianlinbox.com/echo" xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="qualified" elementFormDefault="qualified">
<xs:complexType name="EchoMessageType">
<xs:sequence>
<xs:element name="Message" type="xs:string" minOccurs="1" />
</xs:sequence>
</xs:complexType>
<xs:element name="EchoRequest" type="EchoMessageType"/>
<xs:element name="EchoResponse" type="EchoMessageType"/>
<xs:element name="ReverseEchoRequest" type="EchoMessageType"/>
<xs:element name="ReverseEchoResponse" type="EchoMessageType"/>
</xs:schema>

然后,创建http服务

require 'bundler'
Bundler.setup
require 'sinatra/base'
# XML 解析需用到nokogiri
require 'nokogiri'
require 'builder'

class EchoService < Sinatra::Base

set :root, File.dirname(__FILE__)


# 添加http basic authentication
use Rack::Auth::Basic, "Restricted Area" do |username, password|
username == 'admin' and password == 'admin'
end

# 创建Soap消息异常对象
module SoapFault
class MustUnderstandError < StandardError
def fault_code
"MustUnderstand"
end
end

class ClientError < StandardError
def fault_code
"Client"
end
end
end
# SOAP要求SOAP messages使用Content-Type:text/xml,Sinatra默认的是application/xml,因此需配置。
configure do
mime_type :xml, "text/xml"
end

#xsd读取request和response的schema, xslt用于从soap message中获取消息体,
def initialize(*args)
@xsd = Nokogiri::XML::Schema(File.read("#{File.dirname(__FILE__)}/public/echo_service.xsd"))
@xslt = Nokogiri::XSLT(File.read("#{File.dirname(__FILE__)}/lib/soap_body.xslt"))
super
end

# SOAP endpoint
post '/echo_service' do
begin
soap_message = Nokogiri::XML(request.body.read)
# 通过消息头来判断是否是当前服务可处理的消息。
raise(SoapFault::MustUnderstandError, "SOAP Must Understand Error", "MustUnderstand") if soap_message.root.at_xpath('//soap:Header/*[@soap:mustUnderstand="1" and not(@soap:actor)]', 'soap' => 'http://schemas.xmlsoap.org/soap/envelope/')
# 获取消息体
soap_body = @xslt.transform(soap_message)
# 通过schema验证request的结构是否合法。
errors = @xsd.validate(soap_body).map { |e| e.message }.join(", ")
# 如果request格式不正确,抛错。
raise(SoapFault::ClientError, errors) unless errors == ""
# 从request中获取该request请求的操作,通过动态分发的方式发送到对应的处理方法。
self.send(soap_operation_to_method(soap_body), soap_body)
rescue StandardError => e
fault_code = e.respond_to?(:fault_code) ? e.fault_code : "Server"
halt(500, builder(:fault, :locals => {:fault_string => e.message, :fault_code => fault_code}))
end
end

private

# 解析消息体获取request请求的操作。
def soap_operation_to_method(soap_body)
method = soap_body.root.name.sub(/Request$/, '').gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase.to_sym
end

# Echo服务的具体处理函数
def echo(soap_body)
message = soap_body.root.at_xpath('//echo:Message/text()', 'echo' => 'http://www.without-brains.net/echo').to_s
builder(:echo_response, :locals => {:message => message})
end

# ReverseEcho服务的具体处理函数
def reverse_echo(soap_body)
message = soap_body.root.at_xpath('//echo:Message/text()', 'echo' => 'http://www.without-brains.net/echo').to_s.reverse!
builder(:reverse_echo_response, :locals => {:message => message})
end
end


通过使用builder可以更方便的构建response的内容,
Fault Builder
xml.SOAP(:Envelope, "xmlns:SOAP" => "http://schemas.xmlsoap.org/soap/envelope/") do
xml.SOAP :Body do
xml.SOAP :Fault do
xml.faultcode "SOAP:#{fault_code}"
xml.faultstring fault_string
end
end
end


EchoResponse Builder
xml.SOAP(:Envelope, "xmlns:SOAP" => "http://schemas.xmlsoap.org/soap/envelope/", "xmlns:echo" => "http://www.without-brains.net/echo") do
xml.SOAP :Body do
xml.echo :EchoResponse do
xml.echo(:Message, message)
end
end
end


ReverseEchoRespose Builder
xml.SOAP(:Envelope, "xmlns:SOAP" => "http://schemas.xmlsoap.org/soap/envelope/", "xmlns:echo" => "http://www.without-brains.net/echo") do
xml.SOAP :Body do
xml.echo :ReverseEchoResponse do
xml.echo(:Message, message)
end
end
end


That's all!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值