Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2011.12.18;
Скачать: [xml.tar.bz2];

Вниз

Отправка Soap Headers   Найти похожие ветки 

 
Servy ©   (2011-09-05 13:10) [0]

Возникла необходимость написать клиент к одному SOAP-сервису. От авторов сервиса пришел пример, как должен выглядеть запрос, он приведен ниже. Я заменил url сервиса заказчика на "http://serviceurl/", ибо он длинный и не должен быть доступен широкой публике:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://serviceurl/" xmlns:ns2="redeemVoucher">
 <SOAP-ENV:Header>
  <ns2:Authorization>Basic b2N0b2JlcjoxMjM0</ns2:Authorization>
 </SOAP-ENV:Header>
 <SOAP-ENV:Body>
  <ns1:redeemVoucher>
  <partner_id>26538</partner_id>
  <voucher_id>9910000000980</voucher_id>
  <timeout>20</timeout>
  <transaction_data>Some data here
  </transaction_data>
  </ns1:redeemVoucher>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

В Делфи я экспортнул wsdl"ку. Header в wsdl"ке не описан. Прочитав:

http://docwiki.embarcadero.com/RADStudio/en/Defining_and_Using_SOAP_Headers

Я написал следующий код:

TAuthHeader = class(TSOAPHeader)
private
 FAuthorization: string;
published
 property Authorization: string read FAuthorization write FAuthorization;
end;

// ...

initialization
 { VoucherService }
 InvRegistry.RegisterInterface(TypeInfo(VoucherService), "http://serviceurl/", "UTF-8"); // сгенерировано делфи
 
 InvRegistry.RegisterHeaderClass(TypeInfo(VoucherService), TAuthHeader, "Authentification", "");
 RemClassRegistry.RegisterSerializeOptions(TAuthHeader, [xoSimpleTypeWrapper]);
 
При вызове передаю заголовок следующим образом:

function SendRedeemVoucherW(PartnerId: PWideChar; VoucherId: PWideChar;
                           Timeout: Integer;
                           TransactionData: PWideChar): HRESULT;
var
 Headers: ISOAPHeaders;
 H: TAuthHeader;
begin
 LogWrite("redeemVoucher has been called", Standart);

 Headers := PartnerVoucherService as ISOAPHeaders;

 H := TAuthHeader.Create;
 H.Authorization := "Basic b2N0b2JlcjoxMjM0";
 Headers.OwnsSentHeaders := True;
 Headers.Send(H);

 Result := PartnerVoucherService.redeemVoucher(PartnerId, VoucherId,
                                               Timeout, TransactionData);
                                               

При этом, Делфи отправляет следующий запрос (я отформатировал xml, чтобы удобнее было читать):

POST / HTTP/1.1
SOAPAction: ""
Content-Type: text/xml; charset="utf-8"
User-Agent: CodeGear SOAP 1.3
Host: localhost:8333
Content-Length: 652
Connection: Keep-Alive
Cache-Control: no-cache

<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <SOAP-ENV:Header>
  <NS1:TAuthHeader xmlns:NS1="urn:uVoucher">
   <NS1:Authorization>Basic b2N0b2JlcjoxMjM0</NS1:Authorization>
  </NS1:TAuthHeader>
 </SOAP-ENV:Header>
 <SOAP-ENV:Body>
  <redeemVoucher xmlns="http://services.partnergw.servop.ru/">
   <partner_id xmlns="">26538</partner_id>
   <voucher_id xmlns="">9910000000980</voucher_id>
   <timeout xmlns="">10</timeout>
   <transaction_data xmlns="">Some data</transaction_data>
  </redeemVoucher>
 </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Сервис возвращает ошибку авторизации. Собственно вопрос - как передать soap-header так, как этого ждет сервис заказчика:

 <SOAP-ENV:Header>
  <ns2:Authorization>Basic b2N0b2JlcjoxMjM0</ns2:Authorization>
 </SOAP-ENV:Header>

А не так, как это происходит при использовании вышеприведенного кода, написанного (ну, я старался ^_^) согласно справке:

 <SOAP-ENV:Header>
  <NS1:TAuthHeader xmlns:NS1="urn:uVoucher">
   <NS1:Authorization>Basic b2N0b2JlcjoxMjM0</NS1:Authorization>
  </NS1:TAuthHeader>
 </SOAP-ENV:Header>


Есть злобный вариант - просто открыть сокет и писать туда все руками так, как этого ждет сервис. Но формирование SOAP запроса руками видится мне костылем, и убивает всю "идею" соапа.

P.S. Мои знания технологии SOAP, и тем более особенностей ее реализации в Делфи далеки до идеала.


 
Servy ©   (2011-09-07 01:07) [1]

На случай, если кто-то найдет этот тред поиском, поделюсь воплощенным решением:

После копания генофонда, выяснилось, что добавлять чужие xmlns в SOAP:Envelope делфи не умеет в принципе, кроме того, нормального способа дописать их туда, не меняя пресловутый генофонд, или не используя ужас вроде StringReplace"а получившегося xml"я, не нашлось. Судя по всему, по спецификации SOAP"а, которую я полностью естесственно не осилил, эти самые xmlns можно писать и по месту, так, как это делает Делфи, то есть например так:


<SOAP-ENV:Envelope ...>
<SOAP-ENV:Body>
 <redeemVoucher xmlns="http://serviceurl">


вмето


<SOAP-ENV:Envelope xmlns:ns1="http://serviceurl/" ...>
<SOAP-ENV:Body>
 <ns1:redeemVoucher>


Соответственно, проблема была преобразована в другую: получить от Делфи заголовок вида:


<SOAP-ENV:Header>
 <Authorization xmlns="redeemVoucher">Basic b2N0b2JlcjoxMjM0</Authorization>
</SOAP-ENV:Header>


Так как с помощью опций и другого мелкого вмешательства этого добиться не удалось, пришлось вмешаться в процесс преобразования объект->xml, и написать свой класс заголовка такого вида:


 TAuthHeader = class(TSOAPHeader)
 private
   FAuthorization: string;
 published
   property Authorization: string read FAuthorization write FAuthorization;

 public
   function   ObjectToSOAP(RootNode, ParentNode: IXMLNode;
                           const ObjConverter: IObjConverter;
                           const NodeName, NodeNamespace, ChildNamespace: InvString; ObjConvOpts: TObjectConvertOptions;
                           out RefID: InvString): IXMLNode; override;

 end;

type
 TSOAPDomConvAccess = class(TSOAPDomConv);

function TAuthHeader.ObjectToSOAP(RootNode, ParentNode: IXMLNode;
 const ObjConverter: IObjConverter; const NodeName, NodeNamespace,
 ChildNamespace: InvString; ObjConvOpts: TObjectConvertOptions;
 out RefID: InvString): IXMLNode;
var
 Conv: TSOAPDomConv;
begin
 Result := ParentNode.AddChild("Authorization", "redeemVoucher", False);

 Conv := (ObjConverter as TSOAPDomConv);
 RefId := TSOAPDomConvAccess(Conv).GetNewID;

 Result.Text := FAuthorization;
end;


В результате добавления заголовка такого класса, генерируется требуемый xml, без двойного тега в SOAP-header и с нужным неймспейсом, и сервис на другом конце это дело успешно ест.


 
Плохиш ©   (2011-09-07 11:32) [2]

Стоит разместить это на http://edn.embarcadero.com/



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2011.12.18;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.47 MB
Время: 0.004 c
2-1315480506
LDV
2011-09-08 15:15
2011.12.18
правильное использование транзакций


15-1314785463
Доменик
2011-08-31 14:11
2011.12.18
Помогите с запросом


6-1248848880
Sonoleo
2009-07-29 10:28
2011.12.18
МЭК 80670-5-104


15-1314617994
Юра Погудин
2011-08-29 15:39
2011.12.18
Проблема с форматированием Windows


8-1221298606
Grinya
2008-09-13 13:36
2011.12.18
карта в масштабе





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский