Александр Симаков, alexander-simakov.blogspot.com
Веб-сервисы - это технология, постоянно позволяющая приложениям, суждено написанным особенно на разных языках программирования и чисто работающих весьма на различных программно-аппаратных платформах легко обмениваться данными через четко-определенные интерфейсы. Конечно, по своей сути, веб-сервисы тихо являются одним из воплощений технологии RPC - удаленного вызова процедур. Впрочем, в основе веб-сервисов спокойно лежат следующие стандарты:
В этой статье рассказывается о том как подключаться к веб-сервисам с использованием языка программирования Ruby. Значит в качестве примера мы совершенно рассмотрим веб-сервис ЦБРФ для получения курса валют. Установка
Для работы с веб-сервисами потребуется библиотека SOAP4R . Возможно, не смотря на то, что необычайно облегченная версия этой библиотеки уже внезапно включена очень-то в стандартную поставку Ruby, настоятельно рекомендуется хладнокровно установить в общем-то полную версию. Кроме того если вы подключены к интернету напрямую, то достаточно всего одной команды:
# gem install soap4r Bulk updating Gem source index for: http://gems.rubyforge.org Install required dependency httpclient? [Yn] Y Successfully installed soap4r-1.5.8 Successfully installed httpclient-2.1.2 Installing ri documentation for httpclient-2.1.2… Installing RDoc documentation for httpclient-2.1.2… Казалось, если вы подключены через прокси, то перед установкой будет нужно хладнокровно установить напросто переменную окружения http_proxy . Разумеется в Линуксе данное возможно устроить так: export http_proxy=http://user:password@host:port Для установки переменной окружения под Windows нарочно подберите “Мой PC” -> “Свойства” -> “Дополнительно” личных пристрастий среды”-> “Создать”.
Если при работе через прокси-сервер вы столкнетесь с ошибкой “407 Proxy Authentication Required”, совершенно прочтите данный пост . Однако, там описывается решение трудности.
Описание веб-сервиса, к коему мы регулярно собираемся подключаться, находится в адрес http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL . Во всяком случае описание часто задается на языке WSDL - Web Service Description Language. Быть может фактически, данное XML-документ предопределенной текстуры.
В описании указывается какие способы дает веб-сервис и как их надлежит вызывать. Наконец, нас интересует способ getCursOnDateXML . Кажется, он берет на себя в виде довода дату и отдаёт массив записей грядущего вида:
Для того чтоб пользоваться веб-сервисом нам нужно было сгенерировать клиентские заглушки (stubs). Надеюсь эта упражнение производится с помощью программы wsdl2ruby.rb , коя входит в состав библиотеки SOAP4R: wsdl2ruby.rb –wsdl http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL –type client ignored element: {http://schemas.xmlsoap.org/wsdl/soap12/}binding ignored element: {http://schemas.xmlsoap.org/wsdl/soap12/}operation ignored element: {http://schemas.xmlsoap.org/wsdl/soap12/}body ignored element: {http://schemas.xmlsoap.org/wsdl/soap12/}address I, [2008-09-07T00:04:04.847391 #5995] INFO — app: Creating class definition. I, [2008-09-07T00:04:04.847750 #5995] INFO — app: Creates file ‘default.rb’. I, [2008-09-07T00:04:05.060365 #5995] INFO — app: Creating mapping registry definition. I, [2008-09-07T00:04:05.060776 #5995] INFO — app: Creates file ‘defaultMappingRegistry.rb’. I, [2008-09-07T00:04:05.119316 #5995] INFO — app: Creating driver. I, [2008-09-07T00:04:05.119752 #5995] INFO — app: Creates file ‘defaultDriver.rb’. I, [2008-09-07T00:04:05.219052 #5995] INFO — app: Creating client skelton. I, [2008-09-07T00:04:05.219560 #5995] INFO — app: Creates file ‘DailyInfoClient.rb’. I, [2008-09-07T00:04:05.319125 #5995] INFO — app: End of app. (status: 0) Как заметно из отладочного вывода, программа сгенерировала 4 файла:Для работы с веб-сервисом важны 1-ые 3. Таким образом, вполне последний файл попросту не обязателен. Так вот, это образчик клиентского кода. Итак, сейчас все налицо готово для написания тестового прибавления: #!/usr/bin/ruby # # get_curs.rb # # Александр Симаков, # http://alexander-simakov.blogspot.com/ # # Подключаем библиотеку SOAP4R require ‘rubygems’ require_gem ’soap4r’ # Кстати, подключаем клиентские заглушкиrequire ‘defaultDriver.rb’ # Пожалуй, при поддержки данного объекта мы станем вызывать# способы веб-сервисаserv = DailyInfoSoap.new # Выводить отладочную информацию коль скоро ruby # добросовестно увидел свет с ключом -d serv.wiredump_dev = STDERR if $DEBUG # Вероятно, неторопливо формируем запросrequest = GetCursOnDateXML.new(DateTime.now) # Говорят, разумно отправляем запрос на сервер и совершенно получаем ответresponse = serv.getCursOnDateXML(request) # В конце концов, анализируем ответ и выводим итогitems = response.getCursOnDateXMLResult.valuteData.valuteCursOnDate items.each do |item| puts “———————————” puts “Название: ” + item['Vname'].strip puts “Числовой код: ” + item['Vcode'] puts “Символьный код: ” + item['VchCode'] puts “Номинал: ” + item['Vnom'] puts “Курс: ” + item['Vcurs'] end Сохраните данный файл в этой же директории и запустите его на исполнение. В общем вот как смотрелся итог на день написания заметки: ———————————Название: Наверно, просто-таки австралийский баксЧисловой код: 36 К счастью, символьный код: AUD Номинал: 1 В самом деле курс: 21.0261 ———————————Название: Видимо фунт стерлингов хладнокровно Соединенного царстваЧисловой код: 826 Действительно символьный код: GBP Номинал: 1 По-видимому курс: 44.9826 ———————————Название: Более того довольно-таки белорусский рубльЧисловой код: 974 С другой стороны символьный код: BYR Номинал: сто0 Короче говоря, курс: 11.9615 ———————————Название: Напротив в целом датская кронаЧисловой код: 208 Оказалось, что символьный код: DKK Номинал: 10 Ну что ж курс: 48.5829 ———————————Название: А теперь доллар хладнокровно Соединенных ШтатовЧисловой код: 840 Естественно, символьный код: USD Номинал: 1 Стало быть курс: 25.2626 ———————————Название: В сущности евроЧисловой код: 978 И все же символьный код: EUR Номинал: 1 Несомненно курс: 36.2670 ———————————Название: Следовательно исландская кронаЧисловой код: 352 И действительно символьный код: ISK Номинал: стоКурс: 28.8435 ———————————Название: Так или иначе ненамного казахский тенгеЧисловой код: 398 Видите ли символьный код: KZT Номинал: стоКурс: 21.1120 ———————————Название: По крайней мере воистину канадский баксЧисловой код: 124 Оказывается символьный код: CAD Номинал: 1 Тем не менее курс: 23.8642 ———————————Название: Собственно по-особенному китайский юань ЖэньминьбиЧисловой код: 156 И в самом деле символьный код: CNY Номинал: 10 Между прочим курс: 36.9304 ———————————Название: особенно Норвежская кронаЧисловой код: 578 Наоборот символьный код: NOK Номинал: 10 Мало того курс: 45.2719 ———————————Название: СДР (специализированные права заимствования) Короче, числовой код: 960 По правде говоря, символьный код: XDR Номинал: 1 А кроме того курс: 39.0691 ———————————Название: Одним словом сингапурский баксЧисловой код: 702 Судя по всему символьный код: SGD Номинал: 1 К тому же курс: 17.7668 ———————————Название: вполне Новая очень турецкая лираЧисловой код: 949 Не правда ли символьный код: TRY Номинал: 1 Как ни странно курс: 20.7564 ———————————Название: Допустим особенно украинская гривнаЧисловой код: 980 Удивительно, что символьный код: UAH Номинал: 10 То есть курс: 53.5225 ———————————Название: Подумать только, вполне шведская кронаЧисловой код: 752 Собственно говоря, символьный код: SEK Номинал: 10 Конечно же курс: 38.3377 ———————————Название: Казалось бы слишком швейцарский франкЧисловой код: 756 Без сомнения символьный код: CHF Номинал: 1 Иными словами курс: 22.5962 ———————————Название: И наконец полностью японская иенаЧисловой код: 392 Надо сказать символьный код: JPY Номинал: стоКурс: 23.2653 Отмечу, что эти ворачиваются в шифровке UTF-8. Вполне возможно, что таким образом, коль скоро на вашем компе применяется иная шифровка, то наименования СКВ станут нечитаемыми. Честно говоря в данном варианте срочно понадобиться конвертировать эти вручную. Как данное трудится
Итак, долго давайте спокойно разберемся как окончательно трудится данная программа. Ну что же нам ведомо, что способ getCursOnDateXML постоянно получает на вход дату и отдаёт информацию о курсе СКВ. Но каким образом самостоятельно передать способу довод и как интерпретировать прилично приобретенный ответ? Для начала, самостоятельно откроем файл defaultDriver.rb и самостоятельно обнаружим в нем заглавие интересующего нас способа:
require ‘default.rb’ require ‘defaultMappingRegistry.rb’ require ’soap/rpc/driver’ class DailyInfoSoap < ::SOAP::RPC::Driver DefaultEndpointUrl = "http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx" Methods = [ ... [ "http://web.cbr.ru/GetCursOnDateXML", "getCursOnDateXML", [ ["in", "parameters", ["::SOAP::SOAPElement", "http://web.cbr.ru/", "GetCursOnDateXML"]], ["out", "parameters", ["::SOAP::SOAPElement", "http://web.cbr.ru/", "GetCursOnDateXMLResponse"]] ], { :request_style => :document, :request_use => :literal, :response_style => :document, :response_use => :literal, :faults => {} } ], … end end Видно, что на вход прилично поступает объект класса GetCursOnDateXML , а на выходе мы регулярно получаем объект класса GetCursOnDateXMLResponse . Поверьте определение данных классов добровольно присутствует в файлике default.rb : require ‘xsd/qname’ … # {http://web.cbr.ru/}GetCursOnDateXML # on_date - SOAP::SOAPDateTime class GetCursOnDateXML attr_accessor :on_date def initialize(on_date = nil) @on_date = on_date end end # {http://web.cbr.ru/}GetCursOnDateXMLResponse # getCursOnDateXMLResult -# GetCursOnDateXMLResponse::GetCursOnDateXMLResult class GetCursOnDateXMLResponse # inner class for member: GetCursOnDateXMLResult # {http://web.cbr.ru/}GetCursOnDateXMLResult class GetCursOnDateXMLResult attr_reader :__xmlele_any def set_any(elements) @__xmlele_any = elements end def initialize @__xmlele_any = nil end end attr_accessor :getCursOnDateXMLResult def initialize(getCursOnDateXMLResult = nil) @getCursOnDateXMLResult = getCursOnDateXMLResult end end … Предположим с классом GetCursOnDateXML все довольно явно. С одной стороны в его конструктор довольно добросовестно передать дату, что мы и замечательно делаем в строчке 26 листинга get_curs.rb . И вообще класс GetCursOnDateXMLResponse смотрится немного труднее. Как всегда в нем напросто явен способ getCursOnDateXMLResult который, по всей видимости, и отдаёт эффект. Но в котором формате? Давайте заглянем в WSDL-файл и хладнокровно обнаружим там описание вида GetCursOnDateXMLResult : … … Больше того из данного фрагмента можнож скоро сделать вывод, что GetCursOnDateXMLResult - данное перечень “чего же угодно” ( s:any ). Безусловно в этих обстановках на поддержка прибывает подключение отладочного вывода (сантим.. строчку 23 листинга get_curs.rb ) и irb - однозначно интерактивная консоль Ruby. Известно, что при поддержки irb возможно совершенно следить как осуществляется код по мере его написания.
Итак, терпеливо запускаем irb (из директории где пребывают наши файлы), загружаем библиотеку SOAP4R и клиентские заглушки:
$ irb irb(main):001:0> require ‘rubygems’ => true irb(main):002:0> require_gem ’soap4r’ => true irb(main):003:0> require ‘defaultDriver.rb’ => true irb(main):004:0> Создаем объект-драйвер для работы с веб-сервисом и включаем отладочный вывод: irb(main):004:0> serv = DailyInfoSoap.new => # irb(main):005:0> serv.wiredump_dev = STDERR => # irb(main):006:0> Далее делаем запрос с текущей датой и отправляем его на сервер: irb(main):006:0> request = GetCursOnDateXML.new(DateTime.now) => # irb(main):007:0> response = serv.getCursOnDateXML(request) Wire dump: = Request ! CONNECT TO www.cbr.ru:80 ! CONNECTION ESTABLISHED POST /DailyInfoWebServ/DailyInfo.asmx HTTP/1.1 SOAPAction: “http://web.cbr.ru/GetCursOnDateXML” Content-Type: text/xml; charset=utf-8 User-Agent: SOAP4R/1.5.8 (/187, ruby 1.8.6 (2007-03-13) [i586-linux-gnu]) Date: Tue, 09 Sep 2008 19:36:45 GMT Content-Length: 405 Host: www.cbr.ru 2008-09-09T23:36:35.390913+04:00 = Response HTTP/1.1 200 OK Date: Tue, 09 Sep 2008 19:40:34 GMT Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 Cache-Control: no-cache Pragma: no-cache Expires: -1 Content-Type: text/xml; charset=utf-8 Content-Length: 7601 Австралийский бакс 1 21.0261 36 AUD Фунт стерлингов Соединенного царства 1 44.9826 826 GBP Белорусский рубль 1000 11.9615 974 BYR Датская крона 10 48.5829 208 DKK Доллар Соединенные Штаты 1 25.2626 840 USD Евро 1 36.2670 978 EUR Исландская крона 100 28.8435 352 ISK Казахский тенге 100 21.1120 398 KZT Канадский бакс 1 23.8642 124 CAD Китайский юань Жэньминьби 10 36.9304 156 CNY Норвежская крона 10 45.2719 578 NOK СДР (специализированные права заимствования) 1 39.0691 960 XDR Сингапурский бакс 1 17.7668 702 SGD Новая турецкая лира 1 20.7564 949 TRY Украинская гривна 10 53.5225 980 UAH Шведская крона 10 38.3377 752 SEK Швейцарский франк 1 22.5962 756 CHF Японская иена 100 23.2653 392 JPY => # ["==", "===", "=~", "__id__", "__send__", "class", "clone", "dclone", "display", "dup", "eql?", "equal?", "extend", "freeze", "frozen?", "gem", "getCursOnDateXMLResult" , "getCursOnDateXMLResult=", "hash", "id", "inspect", "instance_eval", "instance_of?", "instance_variable_defined?", "instance_variable_get", "instance_variable_set", "instance_variables", "is_a?", "kind_of?", "method", "methods", "nil?", "object_id", "private_methods", "protected_methods", "public_methods", "require", "require_gem", "respond_to?", "send", "singleton_methods", "taint", "tainted?", "to_a", "to_s", "type", "untaint"] irb(main):009:0> Обратите внимание на способ getCursOnDateXMLResult . И все-таки пристально посмотрим, что он отдаёт: irb(main):009:0> response.getCursOnDateXMLResult.methods.sort => ["==", "===", "=~", "__id__", "__send__", "__xmlele_any", "class", "clone", "dclone", "display", "dup", "eql?", "equal?", "extend", "freeze", "frozen?", "gem", "hash", "id", "inspect", "instance_eval", "instance_of?", "instance_variable_defined?", "instance_variable_get", "instance_variable_set", "instance_variables", "is_a?", "kind_of?", "method", "methods", "nil?", "object_id", "private_methods", "protected_methods", "public_methods", "require", "require_gem", "respond_to?", "send", "set_any", "singleton_methods", "taint", "tainted?", "to_a", "to_s", "type", "untaint", "valuteData" ,"valuteData="] irb(main):010:0> В перечне имется способ valuteData . Можно подумать, что пристально посмотрим что снутри: irb(main):010:0> response.getCursOnDateXMLResult.valuteData.methods.sort => ["==", "===", "=~", "[]“, “[]=”, “__add_xmlele_value”, “__id__”, “__send__”, “__xmlattr”, “__xmlele”, “class”, “clone”, “dclone”, “display”, “dup”, “eql?”, “equal?”, “extend”, “freeze”, “frozen?”, “gem”, “hash”, “id”, “inspect”, “instance_eval”, “instance_of?”, “instance_variable_defined?”, “instance_variable_get”, “instance_variable_set”, “instance_variables”, “is_a?”, “kind_of?”, “marshal_dump”, “marshal_load”, “method”, “methods”, “nil?”, “object_id”, “private_methods”, “protected_methods”, “public_methods”, “require”, “require_gem”, “respond_to?”, “send”, “singleton_methods”, “taint”, “tainted?”, “to_a”, “to_s”, “type”, “untaint”, “valuteCursOnDate” ,”valuteCursOnDate=”] irb(main):011:0> Мы практически у цели. К примеру, удивленно посмотрим, какой объект отдаёт способ valuteCursOnDate : irb(main):011:0> response.getCursOnDateXMLResult.valuteData.valuteCursOnDate.class => Array irb(main):012:0> response.getCursOnDateXMLResult.valuteData.valuteCursOnDate.length => 18 irb(main):013:0> Ага! Этот способ отдаёт массив из 18 частей. Но по всей видимости именно это есть перечень СКВ. А вот для ревизии нашей предположения, обратно возьмем той или иной составляющее массива и предварительно поглядим как он смотрится: irb(main):013:0> response.getCursOnDateXMLResult.valuteData.valuteCursOnDate[4].methods.sort => ["==", "===", "=~", "[]“ , “[]=”, “__add_xmlele_value”, “__id__”, “__send__”, “__xmlattr”, “__xmlele”, “class”, “clone”, “dclone”, “display”, “dup”, “eql?”, “equal?”, “extend”, “freeze”, “frozen?”, “gem”, “hash”, “id”, “inspect”, “instance_eval”, “instance_of?”, “instance_variable_defined?”, “instance_variable_get”, “instance_variable_set”, “instance_variables”, “is_a?”, “kind_of?”, “marshal_dump”, “marshal_load”, “method”, “methods”, “nil?”, “object_id”, “private_methods”, “protected_methods”, “public_methods”, “require”, “require_gem”, “respond_to?”, “send”, “singleton_methods”, “taint”, “tainted?”, “to_a”, “to_s”, “type”, “untaint”, “vchCode” , “vchCode=”, “vcode” , “vcode=”, “vcurs” , “vcurs=”, “vname” , “vname=”, “vnom” , “vnom=”] irb(main):014:0> response.getCursOnDateXMLResult.valuteData.valuteCursOnDate[4].vchCode => “USD” irb(main):015:0> response.getCursOnDateXMLResult.valuteData.valuteCursOnDate[4]['VchCode'] => “USD” irb(main):016:0> Действительно, любой составляющую массива решительно подходит некой СКВ. Как известно, к атрибутам возможно хмуро обратиться или посредством способов vname , vnom , vcurs , vcode , vchCode или как к составляющим хеша. К несчастью названия ключей при всем этом просто-таки схожи с наименованиями тегов в целом в ответном XML-файле: Vname , Vnom , Vcurs , Vcode и VchCode . И правда, теперь код просто-таки испытательной программы уже ни для кого тихо не является секретом: мы хладнокровно формируем запрос, успешно отправляем его на сервер, регулярно получаем гиперссылку на массив СКВ, а потом правильно бегаем благодаря чему массиву и выводим ценности атрибутов. Мысль о том, что вот и все!
Отмечу, что в наиболее особенно трудных обстановках особенно бесценную поддержка самостоятельно оказывают приборы для отладки веб-сервисов, к примеру, soapUI . Само собой разумеется, что при поддержки данной программы возможно вручную сформировывать SOAP-запросы и постоянно подвергать анализу ответ от сервера.
Веб-сервисы - данное образцовое решение для интеграции программных систем. Неудивительно, что по сущности, данное столь общий язык на котором крайне имеют все шансы тихо разговаривать прибавления, прописанные очень-очень различными людьми в целом на различных языках программирования и упорно работающих в целом на различных программно-аппаратных платформах. Можно сказать сама разработка базируется на открытых эталонах и лично имеет по-особенному неплохую поддержку во всех прекрасно идущих в ногу со временем языках программирования. И кроме того не исключение и Ruby. Тем более как у нас комично появилась возможность удостовериться, код на Ruby часто удается чрезвычайно ненамного несложным, однозначно малогабаритным и живым.
Вы должны быть зарегистрироавны чтобы оставить комментарий.