Размещение данных и получение ответа для клиента SOAP - PullRequest
4 голосов
/ 31 января 2012

Почти весь мой опыт разработки был в настольных приложениях. В настоящее время я использую Delphi 2010, и мне нужно написать SOAP-клиент для доступа к веб-службе, которую калифорнийский EDD поддерживает для электронной обработки данных заработной платы. Я отказался от Delphi WSDL Importer, потому что за кулисами происходило слишком много, и я, похоже, не смог добиться какого-либо прогресса. Я скачал Fiddler2 и использовал это, чтобы посмотреть, что я пишу в Интернете. Я нашел эту процедуру для публикации, и я чувствую, что я получаю куда-то сейчас.

//from StackOverflow Andreas Rejbrand 06/04/2012
procedure WebPostData(const UserAgent: string; const Server: string; const Resource: string; const Data: AnsiString); overload;
    var
      hInet: HINTERNET;
      hHTTP: HINTERNET;
      hReq: HINTERNET;
    const
      accept: packed array[0..1] of LPWSTR = (PChar('*/*'), nil);
      header: string = 'Content-Type: text/plain';
    begin
      hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
      try
        hHTTP := InternetConnect(hInet, PChar(Server), INTERNET_DEFAULT_HTTP_PORT, nil, nil, INTERNET_SERVICE_HTTP, 0, 1);
        try
          hReq := HttpOpenRequest(hHTTP, PChar('POST'), PChar(Resource), nil, nil, @accept, 0, 1);
          try
            if not HttpSendRequest(hReq, PChar(header), length(header), PChar(Data), length(Data)) then
              raise Exception.Create('HttpOpenRequest failed. ' + SysErrorMessage(GetLastError));
          finally
            InternetCloseHandle(hReq);
          end;
        finally
          InternetCloseHandle(hHTTP);
        end;
      finally
        InternetCloseHandle(hInet);
      end;
    end;

Я изменил Content-Type, потому что оригинал, похоже, никогда не вернется.

Я звонил так:

procedure TForm1.Button1Click(Sender: TObject);
var sl: TStringList;
    s: String;
begin
  sl := TStringList.Create;
  sl.LoadFromFile('C:\Documents and Settings\Jack\Desktop\My Reading\FSET Development\Ping.xml');
  s := sl.Text;
  sl.Free;
  WebPostData('BNWebSvc', 'FSETTESTPROD.EDD.CA.GOV','fsetservice', s);
end;

В моем браузере хост (FSETTESTPROD.EDD.CA.GOV) существует и отвечает, что он доступен. Когда я публикую сообщение, я получаю сообщение об ошибке 404, возможно, потому что добавлено имя веб-службы. В Fiddler2 вывод выглядит так:

POST http://FSETTESTPROD.EDD.CA.GOV/fsetservice HTTP/1.1
Accept: */*
Content-Type: text/plain
User-Agent: BNWebSvc
Host: FSETTESTPROD.EDD.CA.GOV
Content-Length: 2190
Pragma: no-cache
Cookie: __utma=158387685.1851397844.1321382260.1321382260.1321382260.1; __utmz=158387685.1321382260.1.1.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=calif%20edd%20eft%20payroll%20processor%20batch%20processing

<?xml version="1.0" encoding="utf-8"?>
<log>
  <inputMessage utc="3/2/2007 10:45:44 PM" messageId="urn:uuid:c07c9aef-28db-4843-8dfc-c5b4d3dc363b">
    <processingStep description="Unprocessed message">
      <soap:Envelope xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <soap:Header>
          <wsa:Action>//edd.ca.gov/Ping</wsa:Action>
          <wsa:MessageID>urn:uuid:c07c9aef-28db-4843-8dfc-c5b4d3dc363b</wsa:MessageID>
          <wsa:ReplyTo>
            <wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>
          </wsa:ReplyTo>
          <wsa:To>http://localhost:3031/EDD.DMRC.FSET.WebServices/FsetService.asmx</wsa:To>
          <wsse:Security soap:mustUnderstand="1">
            <wsu:Timestamp wsu:Id="Timestamp-0983e8c1-e822-4648-8066-33839f54a6a0">
              <wsu:Created>2007-03-02T22:45:41Z</wsu:Created>
              <wsu:Expires>2007-03-02T22:50:41Z</wsu:Expires>
            </wsu:Timestamp>
            <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-0d55d82c-d16d-4c0e-826b-21bf7c805a0f">
              <wsse:Username>MyUserName</wsse:Username>
              <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">MyPassword</wsse:Password>
              <wsse:Nonce>w6dgDz1DMzKntFsFdEcjhw==</wsse:Nonce>
              <wsu:Created>2007-03-02T22:45:41Z</wsu:Created>
            </wsse:UsernameToken>
          </wsse:Security>
        </soap:Header>
        <soap:Body>
          <Ping xmlns="http://edd.ca.gov/">
          </Ping>
        </soap:Body>
      </soap:Envelope>
    </processingStep>
  </inputMessage>
</log>

Мне нужно будет отправить это с использованием HTTPS, когда это работает, и мне, вероятно, нужно включить это, чтобы оно заработало.

Я иду в правильном направлении?

Процедура от Андреаса не указала, как получить ответ. Как мне получить ответ?

Ответы [ 2 ]

1 голос
/ 31 января 2012

Я думаю, что я делаю некоторые успехи. Я изменил WebPostData на функцию и скопировал некоторый код из другого места, чтобы использовать SSL и вернуть результат. Теперь это выглядит так:

function WebPostData(const UserAgent: string; const Server: string; const Resource: string; const Data: AnsiString): String;
var
  hInet: HINTERNET;
  hHTTP: HINTERNET;
  hReq: HINTERNET;
  BufStream: TMemoryStream;
  BytesRead: Cardinal;
  aBuffer     : Array[0..4096] of Char;
  flags       : DWord;
const
  accept: packed array[0..1] of LPWSTR = (PChar('*/*'), nil);
  header: string = 'Content-Type: text/plain';
begin
  hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  try
    hHTTP := InternetConnect(hInet, PChar(Server), INTERNET_DEFAULT_HTTPS_PORT, nil, nil, INTERNET_SERVICE_HTTP, 0, 1);
    try
      flags := INTERNET_FLAG_SECURE or INTERNET_FLAG_KEEP_CONNECTION;
      hReq := HttpOpenRequest(hHTTP, PChar('POST'), PChar(Resource), nil, nil, @accept, flags, 1);
      try
        if not HttpSendRequest(hReq, PChar(header), length(header), PChar(Data), length(Data)) then begin
          raise Exception.Create('HttpOpenRequest failed. ' + SysErrorMessage(GetLastError));
        end else begin
           BufStream := TMemoryStream.Create;
            try
              while InternetReadFile(hReq, @aBuffer, SizeOf(aBuffer), BytesRead) do
              begin
                if (BytesRead = 0) then Break;
                BufStream.Write(aBuffer, BytesRead);
              end;

              aBuffer[0] := #0;
              BufStream.Write(aBuffer, 1);
              Result := PChar(BufStream.Memory);
            finally
              BufStream.Free;
            end;
        end;
      finally
        InternetCloseHandle(hReq);
      end;
    finally
      InternetCloseHandle(hHTTP);
    end;
  finally
    InternetCloseHandle(hInet);
  end;
end;

И теперь я получаю два результата в Fiddler, один успешный, а другой нет.

Успешный:

CONNECT fsettestprod.edd.ca.gov:443 HTTP/1.0
User-Agent: BNWebSvc
Host: FSETTESTPROD.EDD.CA.GOV:443
Content-Length: 0
Connection: Keep-Alive
Pragma: no-cache

A SSLv3-compatible ClientHello handshake was found. Fiddler extracted the parameters below.

Major Version: 3
Minor Version: 1
Random: 4F 28 1F 92 96 EA 2C 64 91 59 12 84 D1 F3 F8 ED BA 89 A5 44 94 D6 50 E0 CF 9B FA 12 5F 57 AD EB
SessionID: empty
Ciphers: 
    [0004]  SSL_RSA_WITH_RC4_128_MD5
    [0005]  SSL_RSA_WITH_RC4_128_SHA
    [000A]  SSL_RSA_WITH_3DES_EDE_SHA
    [0009]  SSL_RSA_WITH_DES_SHA
    [0064]  TLS_RSA_EXPORT1024_WITH_RC4_56_SHA
    [0062]  TLS_RSA_EXPORT1024_WITH_DES_SHA
    [0003]  SSL_RSA_EXPORT_WITH_RC4_40_MD5
    [0006]  SSL_RSA_EXPORT_WITH_RC2_40_MD5
    [0013]  SSL_DHE_DSS_WITH_3DES_EDE_SHA
    [0012]  SSL_DHE_DSS_WITH_DES_SHA
    [0063]  TLS_DHE_DSS_EXPORT1024_WITH_DES_SHA  

И неудачный:

POST https://FSETTESTPROD.EDD.CA.GOV/fsetservice HTTP/1.1
Accept: */*
Content-Type: text/plain
User-Agent: BNWebSvc
Host: FSETTESTPROD.EDD.CA.GOV
Content-Length: 2190
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: __utma=158387685.1851397844.1321382260.1321382260.1321382260.1; __utmz=158387685.1321382260.1.1.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=calif%20edd%20eft%20payroll%20processor%20batch%20processing

<?xml version="1.0" encoding="utf-8"?>
<log>
  <inputMessage utc="3/2/2007 10:45:44 PM" messageId="urn:uuid:c07c9aef-28db-4843-8dfc-c5b4d3dc363b">
    <processingStep description="Unprocessed message">
      <soap:Envelope xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <soap:Header>
          <wsa:Action>//edd.ca.gov/Ping</wsa:Action>
          <wsa:MessageID>urn:uuid:c07c9aef-28db-4843-8dfc-c5b4d3dc363b</wsa:MessageID>
          <wsa:ReplyTo>
            <wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>
          </wsa:ReplyTo>
          <wsa:To>http://localhost:3031/EDD.DMRC.FSET.WebServices/FsetService.asmx</wsa:To>
          <wsse:Security soap:mustUnderstand="1">
            <wsu:Timestamp wsu:Id="Timestamp-0983e8c1-e822-4648-8066-33839f54a6a0">
              <wsu:Created>2007-03-02T22:45:41Z</wsu:Created>
              <wsu:Expires>2007-03-02T22:50:41Z</wsu:Expires>
            </wsu:Timestamp>
            <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-0d55d82c-d16d-4c0e-826b-21bf7c805a0f">
              <wsse:Username>***MyUserName***</wsse:Username>
              <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">***MyPassword***</wsse:Password>
              <wsse:Nonce>w6dgDz1DMzKntFsFdEcjhw==</wsse:Nonce>
              <wsu:Created>2007-03-02T22:45:41Z</wsu:Created>
            </wsse:UsernameToken>
          </wsse:Security>
        </soap:Header>
        <soap:Body>
          <Ping xmlns="http://edd.ca.gov/">
          </Ping>
        </soap:Body>
      </soap:Envelope>
    </processingStep>
  </inputMessage>
</log>

Я прошелся по коду и увидел реакцию Фиддлера. Оба сообщения пришли, когда я перешагнул через строку HTTPSendRequest. В моем событии нажатия кнопки я назначаю результаты функции элементу управления memo, но все, что я получаю, это набор квадратов, указывающих непечатаемые символы.

Показывает ли результат, который я получаю, процесс хороший, а контент плохой?

Может ли это все еще быть проблемой, потому что вы не можете получить доступ к WebService таким образом?

Как я могу расшифровать результаты, или это произойдет автоматически, когда я правильно настрою процесс?

0 голосов
/ 01 февраля 2012

Я теперь провел дополнительные исследования, купил приличную книгу по веб-сервисам "Обучи себя веб-сервисам" (спасибо рут Nook) и коротко поговорил с кем-то из агентства, чей веб-сервис я пытаюсь сделать. использовать. Поэтому я думаю, что у меня есть некоторые ответы на вопросы, которые я задавал, и я суммирую их здесь, на случай, если это будет полезно для всех, кто начинает этот же путь. Если вы видите, что я что-то неверно исказил, и вы можете исправить или улучшить его, я был бы признателен, если бы вы нашли время, чтобы ввести свои улучшения.

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

Возможно, вам следует установить Fiddler2 прямо сейчас. Отзывы, которые вы получите от него, будут важны для достижения прогресса.

Файл WSDL может быть полезен для создания клиента веб-служб, но, возможно, нет. Мой опыт работы с импортером Delphi WSDL заключается в том, что он выполняет неполную работу. В статье Википедии о веб-службах есть раздел о больших веб-службах, в котором указывается, что файл WSDL не является необходимым, но может помочь автоматизировать проект клиента веб-службы. Если это не полезно, не используйте его.

Вам не нужно использовать компонент HTTPRIO для доступа к веб-службе. Вы можете использовать модуль WinInet с некоторым кодом, подобным описанному выше, который я использовал для плагиата в некоторых публикациях StackOverflow.

Схемы, указанные в файле WSDL, не обязательно должны существовать в указанных местах. Технически это URI, а не URL (идентификаторы, а не местоположения).

Написание клиента веб-службы вручную может быть приемлемой альтернативой автоматической генерации, когда автоматическая генерация не работает. Кроме того, как и многие решения черного ящика, он работает только тогда, когда работает. Когда это не работает, другого выбора быть не может. Кроме того, вы узнаете больше и сможете лучше контролировать результаты.

Отправка вашего запроса с использованием SSL выглядит автоматически, если вы используете процедуру PostWebData выше. Получение ответа также входит в эту процедуру.

Получение двух ответов, полученных от веб-службы, указывает на то, что мой процесс хорош, но мой контент плохой. Теперь мне нужно изучить фактический конверт SOAP и предоставить приемлемые данные, чтобы перейти к следующему шагу.

Если результаты не будут расшифрованы, когда я выполню следующий шаг, мне придется провести дополнительные исследования.

Надеюсь, это поможет кому-то другому, пытающемуся найти свой путь в веб-сервисах.

...