Organizowanie usług internetowych


czapki 23 lipca 2013 o 13:09

Pisanie aplikacji klient-serwer SOAP w PHP

  • PHP
  • instruktaż

Cześć wszystkim!
Tak się złożyło, że od niedawna zaangażowałem się w rozwój serwisów internetowych. Ale dzisiaj temat nie jest o mnie, ale o tym, jak możemy napisać własny XML Web Service oparty na protokole SOAP 1.2.

Mam nadzieję, że po przeczytaniu tematu będziecie mogli:

  • napisać własną implementację serwerową aplikacji internetowej;
  • napisać własną implementację kliencką aplikacji internetowej;
  • napisz własny opis usługi internetowej (WSDL);
  • wysyłanie przez klienta tablic tego samego typu danych na serwer.
Jak można się domyślić, cała magia zostanie wykonana przy użyciu PHP oraz wbudowanych klas SoapClient i SoapServer. Jako królik będziemy mieli usługę wysyłania wiadomości sms.

1 Stwierdzenie problemu

1.1 Granice

Na początku proponuję zająć się rezultatem, który osiągniemy na końcu tematu. Jak zapowiedziano powyżej, napiszemy usługę do wysyłania wiadomości sms, a dokładniej będziemy otrzymywać wiadomości z różnych źródeł za pomocą protokołu SOAP. Następnie zastanowimy się, w jakiej formie przychodzą na serwer. Proces kolejkowania wiadomości do dalszego wysłania do dostawcy niestety z wielu powodów wykracza poza zakres tego postu.

1.2 Jakie dane zostaną zmienione?

W porządku, mamy granice! Kolejnym krokiem, który należy wykonać, jest podjęcie decyzji, jakie dane będziemy wymieniać między serwerem a klientem. W tym temacie proponuję nie być mądrzejszym przez długi czas i od razu odpowiedzieć sobie na główne pytania:
  • Jakie minimum danych należy przesłać na serwer, aby wysłać wiadomość SMS do abonenta?
  • Jaka jest minimalna ilość danych, która musi zostać wysłana z serwera, aby zaspokoić potrzeby klienta?
Coś mi mówi, że do tego konieczne jest przesłanie:
  • numer telefonu komórkowego i
  • Tekst SMS.
W zasadzie te dwie cechy wystarczą do wysłania, ale od razu wydaje mi się, że sms z życzeniami urodzinowymi przychodzi do Ciebie o godzinie 3 rano, czyli 4! W tej chwili będę bardzo wdzięczna wszystkim za to, że o mnie nie zapomnieli! Dlatego wyślemy również na serwer i
  • data wysłania wiadomości SMS.
Następną rzeczą, którą chciałbym wysłać na serwer jest
  • Typ wiadomości.
Ten parametr nie jest obowiązkowy, ale może nam się bardzo przydać, jeśli szybko musimy powiedzieć szefowi, ilu naszych klientów „zachwyciliśmy się” naszymi wiadomościami, a także narysować piękne statystyki na ten temat.

A jednak o czymś zapomniałem! Jeśli zastanowimy się trochę bardziej, warto zauważyć, że klient może wysłać na serwer jedną wiadomość SMS na raz lub określoną ich liczbę. Innymi słowy, w jednym pakiecie danych może znajdować się od jednego do nieskończoności wiadomości.

W efekcie otrzymujemy, że do wysłania wiadomości SMS potrzebujemy następujących danych:

  • numer telefonu komórkowego,
  • tekst sms,
  • czas wysłania wiadomości SMS do abonenta,
  • typ wiadomości.

Odpowiedzieliśmy na pierwsze pytanie, teraz trzeba odpowiedzieć na drugie pytanie. A może pozwolę sobie trochę oszukać. Dlatego z serwera wyślemy tylko dane logiczne, których wartość ma następujące znaczenie:

  • TRUE - pakiet pomyślnie dotarł do serwera, przeszedł uwierzytelnienie i został umieszczony w kolejce do wysłania do dostawcy sms
  • FAŁSZ - we wszystkich innych przypadkach

Na tym kończy się opis opisu problemu! I na koniec przejdźmy do najciekawszej części - dowiemy się, jaką dziwaczną bestią jest to MYDŁO!

2 Co to jest MYDŁO?

Ogólnie rzecz biorąc, początkowo nie planowałem pisać nic o tym, czym jest SOAP i chciałem ograniczyć się do linków do strony w3.org z niezbędną specyfikacją, a także linków do Wikipedii. Ale na sam koniec postanowiłem napisać krótką referencję o tym protokole.

Swoją historię zacznę od tego, że ten protokół wymiany danych należy do podzbioru protokołów opartych na tzw. paradygmacie RPC (Remote Procedure Call), którego antypodą jest REST (Representational State Transfer, reprezentatywny transfer stanu) . Więcej na ten temat można przeczytać w Wikipedii, linki do artykułów znajdują się na samym końcu tematu. Z tych artykułów musimy zrozumieć, co następuje: „Podejście RPC umożliwia korzystanie z niewielkiej ilości zasobów sieciowych za pomocą dużej liczby metod i złożonego protokołu. W podejściu REST liczba metod i złożoność protokołu są poważnie ograniczone, co może prowadzić do dużej liczby indywidualnych zasobów”. Czyli w stosunku do nas oznacza to, że w przypadku podejścia RPC strona zawsze będzie miała jedno wejście (link) do usługi i jaką procedurę wywołać w celu przetworzenia przychodzących danych przekazujemy wraz z danymi, natomiast z podejściem REST na naszej stronie Strona posiada wiele wejść (linków), z których każdy akceptuje i przetwarza tylko określone dane. Jeśli ktoś czytający wie, jak jeszcze łatwiej wytłumaczyć różnicę w tych podejściach, to koniecznie pisz w komentarzach!

Następną rzeczą, którą musimy wiedzieć o SOAP, jest to, że ten protokół używa tego samego XML jako transportu, co z jednej strony jest bardzo dobre, ponieważ. nasz arsenał od razu zawiera pełną moc stosu technologii opartych na tym języku znaczników, a mianowicie XML-Schema - język opisu struktury dokumentu XML (dzięki Wikipedii!), który umożliwia automatyczną walidację danych przychodzących na serwer od klientów.

I tak, teraz wiemy, że SOAP jest protokołem używanym do implementacji zdalnego wywoływania procedur i używa XML jako transportu! Jeśli czytasz artykuł na Wikipedii, to stamtąd możesz również dowiedzieć się, że może być używany przez dowolny protokół warstwy aplikacji, a nie tylko w połączeniu z HTTP (niestety w tym temacie rozważymy tylko SOAP over HTTP). A wiesz, co w tym wszystkim lubię najbardziej? Jeśli nie ma domysłów, to podpowiem - MYDŁO!… I tak nie ma żadnych domysłów?… Czy na pewno przeczytałeś artykuł na Wikipedii?… Generalnie nie będę Cię dalej torturował. Dlatego od razu przejdę do odpowiedzi: „SOAP (z angielskiego Simple Object Access Protocol - prosty protokół dostęp do obiektów; do specyfikacji 1.2)". Najważniejszym elementem tej linii jest kursywa! Nie wiem jakie wnioski wyciągnąłeś z tego wszystkiego, ale widzę następujące – skoro tego protokołu w żadnym wypadku nie można nazwać „prostym” (a podobno nawet w3 się z tym zgadza), to od wersji 1.2 przestał być w ogóle odszyfrowane! I stał się znany jako MYDŁO, po prostu MYDŁO i kropka.

No dobra, przepraszam, poślizgnął się trochę w bok. Jak pisałem wcześniej, XML jest używany jako transport, a pakiety, które biegną między klientem a serwerem, nazywane są kopertami SOAP. Jeśli weźmiemy pod uwagę uogólnioną strukturę koperty, będzie ona wydawać się bardzo znajoma, ponieważ przypomina strukturę strony HTML. Ma główną sekcję - Osnuć, który zawiera sekcje nagłówek oraz Ciało, lub Wada. W Ciało dane są przesyłane i jest to obowiązkowa część koperty, natomiast nagłówek jest opcjonalne. W nagłówek może być przesyłana autoryzacja lub wszelkie inne dane, które nie są bezpośrednio związane z danymi wejściowymi procedur usługi sieciowej. Zawodowiec Wada nie ma nic specjalnego do powiedzenia, poza tym, że przychodzi do klienta z serwera w przypadku jakichkolwiek błędów.

Na tym kończy się moja ogólna opowieść o protokole SOAP (przyjrzymy się samym kopertom i ich strukturze bardziej szczegółowo, gdy nasz klient i serwer w końcu nauczą się, jak je ze sobą połączyć) i zaczyna się nowa - o towarzyszu SOAP nazywa WSDL(Język opisu usług sieci Web). Tak, tak, właśnie to odstrasza większość z nas przed samą próbą podjęcia i zaimplementowania własnego API na tym protokole. W rezultacie zwykle wymyślamy na nowo nasze koło z JSON jako transportem. Czym więc jest WSDL? WSDL to język opisu usług internetowych i uzyskiwania do nich dostępu, oparty na języku XML (c) Wikipedia. Jeśli z tej definicji całe święte znaczenie tej technologii nie stanie się dla ciebie jasne, postaram się opisać to własnymi słowami!

WSDL został zaprojektowany, aby umożliwić naszym klientom normalną komunikację z serwerem. W tym celu w pliku z rozszerzeniem „*.wsdl” opisane są następujące informacje:

  • Jakie przestrzenie nazw zostały użyte,
  • jakie schematy danych zostały wykorzystane,
  • jakiego rodzaju wiadomości serwis internetowy oczekuje od klientów,
  • które dane należą do jakich procedur serwisu internetowego,
  • Jakie procedury zawiera serwis internetowy,
  • Jak klient powinien wywoływać procedury serwisu internetowego,
  • Na jaki adres mają być wysyłane połączenia od klientów.
Jak widać, ten plik to cała usługa sieciowa. Podając adres pliku WSDL w kliencie, dowiemy się wszystkiego o dowolnej usłudze internetowej! W rezultacie nie musimy wiedzieć absolutnie nic o tym, gdzie znajduje się sama usługa sieciowa. Wystarczy znać lokalizację pliku WSDL! Wkrótce dowiemy się, że SOAP nie jest tak przerażający, jak go malują (c) rosyjskie przysłowie.

3 Wprowadzenie do schematu XML

Teraz wiemy dużo o tym, czym jest SOAP, co jest w nim zawarte i mamy przegląd tego, jaki stos technologii go otacza. Ponieważ SOAP jest przede wszystkim metodą interakcji między klientem a serwerem, a jako transport do niej wykorzystywany jest język znaczników XML, w tym rozdziale zrozumiemy trochę, jak odbywa się automatyczna walidacja danych za pomocą schematów XML.

Głównym zadaniem schematu jest opisanie struktury danych, które będziemy przetwarzać. Wszystkie dane w schematach XML są podzielone na prosty(skalarny) i złożony(struktury) typy. Typy proste obejmują takie typy jak:

  • linia,
  • numer,
  • logiczne,
  • data.
Coś bardzo prostego, bez rozszerzeń w środku. Ich antypoda to złożone typy złożone. Najprostszym przykładem złożonego typu, który przychodzi do głowy każdemu, są przedmioty. Na przykład książka. Książka składa się z właściwości: autor, tytuł, Cena £, Numer ISBN itp. Z kolei te właściwości mogą być zarówno proste, jak i złożone. A zadaniem schematu XML jest jego opisanie.

Proponuję nie posuwać się daleko i pisać schemat XML dla naszej wiadomości sms! Poniżej znajduje się opis xml wiadomości sms:

71239876543 Wiadomość testowa 2013-07-20T12:00:00 12
Nasz schemat typu złożonego będzie wyglądał tak:


Ten wpis brzmi następująco: mamy zmienną „ wiadomość" rodzaj " wiadomość" i istnieje typ złożony o nazwie " wiadomość", który składa się z sekwencyjnego zestawu elementów" telefon" rodzaj strunowy, « tekst" rodzaj strunowy, « data" rodzaj dataCzas, « rodzaj" rodzaj dziesiętny. Te typy są proste i są już zdefiniowane w definicji schematu. Gratulacje! Właśnie napisaliśmy nasz pierwszy schemat XML!

Myślę, że znaczenie elementów " element" oraz " typ złożony» wszystko stało się dla Ciebie mniej więcej jasne, więc nie będziemy się już na nich skupiać i od razu przejdziemy do elementu kompozytora « sekwencja”. Kiedy używamy elementu kompozytora „ sekwencja» informujemy, że elementy w nim zawarte muszą być zawsze w kolejności określonej w schemacie, a także wszystkie są obowiązkowe. Ale nie rozpaczaj! W schematach XML są jeszcze dwa elementy kompozytora: wybór" oraz " wszystko”. Kompozytor wybór" wskazuje, że powinien być jeden z wymienionych w nim elementów, a kompozytor" wszystko» – dowolna kombinacja wymienionych elementów.

Jak pamiętacie, w pierwszej części tematu ustaliliśmy, że pakiet może być przesyłany od jednego do nieskończoności wiadomości sms. Dlatego proponuję zrozumieć, jak takie dane są deklarowane w schemacie XML. Ogólna struktura pakietu może wyglądać tak:

71239876543 Komunikat testowy 1 2013-07-20T12:00:00 12 71239876543 Komunikat testowy N 2013-07-20T12:00:00 12
Schemat dla tak złożonego typu wyglądałby tak:


Pierwszy blok zawiera znajomą deklarację typu złożonego „ wiadomość”. Jeśli zauważysz, to w każdym prostym typie zawartym w „ wiadomość”, dodano nowe atrybuty kwalifikujące „ minWystępuje" oraz " maxWystępuje”. Jak nietrudno odgadnąć z nazwy, pierwszy ( minWystępuje) wskazuje, że dana sekwencja musi zawierać co najmniej jeden element typu „ telefon», « tekst», « data" oraz " rodzaj”, podczas gdy następny ( maxWystępuje Atrybut ) deklaruje nam, że w naszej sekwencji występuje co najwyżej jeden taki element. W rezultacie, kiedy piszemy nasze schematy dla dowolnych danych, mamy najszerszy wybór, jak je skonfigurować!

Drugi blok schematu deklaruje element „ Lista wiadomości" rodzaj " Lista wiadomości”. Jest oczywiste, że " Lista wiadomości' jest typem złożonym, który zawiera co najmniej jeden element ' wiadomość”, ale maksymalna liczba takich elementów nie jest ograniczona!

4 Pisanie swojego WSDL

Pamiętasz, że WSDL to nasza usługa internetowa? Mam nadzieję, że pamiętasz! Gdy to napiszemy, nasz mały serwis internetowy będzie na nim pływał. Więc radzę nie oszukiwać.

Generalnie, aby wszystko działało dla nas poprawnie, musimy przesłać do klienta plik WSDL z poprawnym typem MIME. W tym celu należy odpowiednio skonfigurować serwer WWW, a mianowicie ustawić typ MIME dla plików z rozszerzeniem *.wsdl na następujący wiersz:

Aplikacja/wsdl+xml
Ale w praktyce zazwyczaj wysyłam nagłówek HTTP przez PHP ” tekst/xml»:

Header("Content-Type: text/xml; charset=utf-8");
i wszystko działało świetnie!

Chcę Cię od razu ostrzec, nasz prosty serwis internetowy będzie miał dość imponujący opis, więc nie przejmuj się, ponieważ. większość tekstu to obowiązkowa woda i raz napisana może być stale kopiowana z jednego serwisu internetowego do drugiego!

Ponieważ WSDL to XML, to w pierwszym wierszu musisz napisać o nim bezpośrednio. Główny element pliku musi zawsze mieć nazwę „ definicje»:


Zazwyczaj WSDL składa się z 4-5 głównych bloków. Pierwszym blokiem jest definicja usługi internetowej lub innymi słowy punkt wejścia.


Tutaj jest napisane, że mamy usługę o nazwie - " Usługa SMS”. W zasadzie wszystkie nazwy w pliku WSDL możesz zmienić na dowolne, ponieważ nie odgrywają absolutnie żadnej roli.

Następnie oświadczamy, że w naszym serwisie internetowym „ Usługa SMS" istnieje punkt wejścia ("port"), który nazywa się " SmsServicePort”. Do tego punktu wejścia będą wysyłane wszystkie żądania od klientów do serwera. I określamy w elemencie " adres zamieszkania» link do pliku handler'a, który zaakceptuje zgłoszenia.

Po zdefiniowaniu usługi sieciowej i określeniu dla niej punktu wejścia, musimy powiązać z nią obsługiwane procedury:


Aby to zrobić, wypisuje, które operacje iw jakiej formie zostaną wywołane. Tych. do portu SmsServicePort» oprawa o nazwie « SmsServiceBinding", który ma typ połączenia " RPC”, a jako protokół przesyłania (transportu) używany jest HTTP. Dlatego zaznaczyliśmy tutaj, że wykonamy wywołanie RPC przez HTTP. Następnie opisujemy, które procedury ( operacja) są obsługiwane w serwisie internetowym. Wesprzemy tylko jedną procedurę - " Wyślij SMS”. Dzięki tej procedurze nasze wspaniałe wiadomości zostaną wysłane na serwer! Po ogłoszeniu procedury należy wskazać, w jakiej formie dane będą przekazywane. W takim przypadku określono, że zostaną użyte standardowe koperty SOAP.

Następnie musimy powiązać procedurę z komunikatami:


W tym celu określamy, że nasze powiązanie („binding”) jest typu „ Typ portu usługi SMS" i w żywiole " typ portu» o tej samej nazwie typu, określić powiązanie procedur z komunikatami. I tak przychodząca wiadomość (od klienta do serwera) będzie nazywać się „ sendSmsRequest"i wychodzące (z serwera do klienta)" sendSmsResponse”. Jak wszystkie nazwy w WSDL, nazwy wiadomości przychodzących i wychodzących są dowolne.

Teraz musimy opisać same wiadomości, tj. przychodzące i wychodzące:


Aby to zrobić, dodajemy elementy „ wiadomość» z imionami « sendSmsRequest" oraz " sendSmsResponse odpowiednio. W nich wskazujemy, że na wejście powinna przyjść koperta, której struktura odpowiada typowi danych " Żądanie”. Następnie z serwera zwracana jest koperta zawierająca typ danych - " Odpowiedź».

Teraz musimy zrobić tylko trochę - dodać opis tych typów do naszego pliku WSDL! A jak myślisz, jak WSDL opisuje dane przychodzące i wychodzące? Myślę, że już dawno wszystko zrozumiałeś i powiedziałeś sobie, że za pomocą schematów XML! I będziesz miał absolutną rację!


Możesz nam pogratulować! Nasz pierwszy WSDL został napisany! I jesteśmy o krok bliżej do osiągnięcia naszego celu.
Następnie zajmiemy się tym, co PHP dostarcza nam do tworzenia własnych aplikacji rozproszonych.

5 Nasz pierwszy serwer SOAP

Wcześniej pisałem, że do stworzenia serwera SOAP w PHP wykorzystamy wbudowaną klasę SoapServer. Aby wszystkie dalsze działania przebiegały w taki sam sposób jak moje, będziesz musiał trochę podrasować PHP. Aby być jeszcze bardziej precyzyjnym, musisz upewnić się, że masz zainstalowane rozszerzenie "php-soap". Jak umieścić go na serwerze WWW najlepiej przeczytać na oficjalnej stronie PHP (patrz referencje).

Po zainstalowaniu i skonfigurowaniu wszystkiego będziemy musieli utworzyć plik „ smsservice.php» o treści:

setClass("SoapSmsGateWay"); //Uruchom serwer $server->handle();
To, co jest powyżej linii z funkcją „ini_set”, mam nadzieję, nie wymaga wyjaśnienia. Dlatego definiuje jakie nagłówki HTTP wyślemy z serwera do klienta oraz konfiguruje środowisko. W wierszu „ini_set” wyłączamy buforowanie pliku WSDL, aby nasze zmiany w nim od razu zaczęły obowiązywać u klienta.

Teraz przychodzimy na serwer! Jak widać, cały serwer SOAP ma tylko trzy linie! W pierwszym wierszu tworzymy nową instancję obiektu SoapServer i przekazujemy adres naszego opisu usługi sieciowej WSDL do jej konstruktora. Teraz wiemy, że będzie on zlokalizowany w katalogu głównym hostingu w pliku o wymownej nazwie " smsservice.wsdl.php”. W drugim wierszu mówimy serwerowi SOAP, którą klasę pobrać, aby przetworzyć kopertę otrzymaną od klienta i zwrócić kopertę z odpowiedzią. Jak można się domyślić, to właśnie w tej klasie zostanie opisana nasza jedyna metoda. Wyślij SMS. W trzeciej linii uruchamiamy serwer! Wszystko, nasz serwer jest gotowy! Z czym nam wszystkim gratuluję!

Teraz musimy stworzyć plik WSDL. Aby to zrobić, możesz po prostu skopiować jego zawartość z poprzedniej sekcji lub pozwolić sobie na trochę „szablonu”:

"; ?> /" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http:// schemas.xmlsoap.org/wsdl/http/" name="SmsWsdl" xmlns="http://schemas.xmlsoap.org/wsdl/"> /"> /smsservice.php" />
Na tym etapie wynikowy serwer powinien nam całkowicie odpowiadać, ponieważ. możemy rejestrować przychodzące do niego koperty, a następnie spokojnie analizować napływające dane. Aby otrzymać cokolwiek na serwerze, potrzebujemy klienta. Więc zajmijmy się nimi!

6 Klient SOAP w drodze

Przede wszystkim musimy stworzyć plik, w którym napiszemy klienta. Jak zwykle utworzymy go w katalogu głównym hosta i nazwiemy go " klient.php”, a w środku piszemy:

ListaWiadomości = nowa ListaWiadomości(); $req->messageList->message = nowa wiadomość(); $req->messageList->message->telefon = "79871234567"; $req->messageList->message->text = "Testuj wiadomość 1"; $req->messageList->message->data = "2013-07-21T15:00:00.26"; $req->messageList->message->type = 15; $client = new SoapClient("http://($_SERVER["HTTP_HOST"])/smsservice.wsdl.php", array("soap_version" => SOAP_1_2)); var_dump($client->sendSms($req));
Opiszmy nasze obiekty. Kiedy pisaliśmy WSDL, opisano w nim trzy encje dla koperty wchodzącej na serwer: Żądanie, Lista wiadomości oraz wiadomość. W związku z tym zajęcia Żądanie, Lista wiadomości oraz wiadomość są odzwierciedleniem tych encji w naszym skrypcie PHP.

Po zdefiniowaniu obiektów musimy utworzyć obiekt ( $wymaganie), które zostaną wysłane na serwer. Następnie przyjdź dla nas dwie najbardziej cenione linie! Nasz klient SOAP! Wierzcie lub nie, ale to wystarczy, aby nasz serwer zaczął napływać wiadomości od klienta, a nasz serwer z powodzeniem je odbierał i przetwarzał! W pierwszym z nich tworzymy instancję klasy SoapClient i przekazujemy adres lokalizacji pliku WSDL do jej konstruktora oraz jednoznacznie wskazujemy w parametrach, że będziemy pracować z wykorzystaniem protokołu SOAP w wersji 1.2. W następnym wierszu wywołujemy metodę Wyślij SMS obiekt $klient i natychmiast wyświetlaj wynik w przeglądarce.
Uruchommy to i zobaczmy, co w końcu dostaliśmy!

Otrzymałem z serwera następujący obiekt:

Object(stdClass) public "status" => wartość logiczna prawda
I to jest cudowne, bo. teraz wiemy na pewno, że nasz serwer działa i nie tylko działa, ale także może zwrócić klientowi pewne wartości!

Teraz spójrzmy na dziennik, który ostrożnie trzymamy po stronie serwera! W pierwszej jego części widzimy surowe dane, które weszły na serwer:

79871234567 Komunikat testowy 1 2013-07-21T15:00:00.26 15
To jest koperta. Teraz wiesz, jak to wygląda! Ale raczej nie będziemy zainteresowani ciągłym podziwianiem tego, więc zdeserializujmy obiekt z pliku dziennika i zobaczmy, czy wszystko jest u nas w porządku:

Object(stdClass) public "messageList" => object(stdClass) public "message" => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Wiadomość testowa 1 " (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public "type" => string "15" (length=2)
Jak widać, obiekt został poprawnie zdeserializowany, czego serdecznie gratuluję! Następnie czeka nas coś ciekawszego! Mianowicie wyślemy przez klienta na serwer nie jedną wiadomość sms, ale całą paczkę (a dokładniej trzy całe)!

7 Wysyłanie złożonych obiektów

Zastanówmy się, jak możemy wysłać całą masę wiadomości na serwer w jednej paczce? Prawdopodobnie najprostszym sposobem byłoby zorganizowanie tablicy wewnątrz elementu messageList! Zróbmy to:

// utwórz obiekt do wysłania na serwer $req = new Request(); $req->messageList = new MessageList(); $msg1 = nowa wiadomość(); $msg1->telefon = "79871234567"; $msg1->text = "Wiadomość testowa 1"; $msg1->data = "2013-07-21T15:00:00.26"; $msg1->typ = 15; $msg2 = nowa wiadomość(); $msg2->telefon = "79871234567"; $msg2->text = "Wiadomość testowa 2"; $msg2->data = "2014-08-22T16:01:10"; $msg2->typ = 16; $msg3 = nowa wiadomość(); $msg3->telefon = "79871234567"; $msg3->text = "Wiadomość testowa 3"; $msg3->data = "2014-08-22T16:01:10"; $msg3->typ = 17; $req->messageList->message = $msg1; $req->messageList->message = $msg2; $req->messageList->message = $msg3;
Z naszych dzienników wynika, że ​​od klienta pochodzi następujący pakiet:

79871234567 Komunikat testowy 1 2013-07-21T15:00:00.26 15 79871234567 Wiadomość testowa 2 2014-08-22T16:01:10 16 79871234567 Komunikat testowy 3 2014-08-22T16:01:10 17
Co za bzdury, mówisz? I w pewnym sensie będziesz miał rację, ponieważ. tak jak dowiedzieliśmy się, który przedmiot opuścił klienta, trafił na nasz serwer w postaci koperty w absolutnie tej samej formie. To prawda, że ​​wiadomości sms nie były serializowane w XML-u tak, jak tego potrzebowaliśmy - musiały być opakowane w elementy wiadomość, nie w Struktura. Zobaczmy teraz, w jakiej postaci taki obiekt przychodzi do metody Wyślij SMS:

Object(stdClass) public "messageList" => object(stdClass) public "message" => object(stdClass) public "Struct" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Wiadomość testowa 1" (length=37) public "data" => string "2013-07-21T15:00:00.26" (length=22) public " type" => string "15" (length=2) 1 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Wiadomość testowa 2" (length= 37) public "data" => string "2014-08-22T16:01:10" (length=19) public "type" => string "16" (length=2) 2 => object(stdClass) public "telefon " => string "79871234567" (długość=11) public "text" => string "Wiadomość testowa 3" (length=37) public "data" => string "2014-08-22T16:01:10" (długość= 19) public "type" => string "17" (długość=2)
Co daje nam ta wiedza? Tyle tylko, że wybrana przez nas ścieżka jest nieprawidłowa i nie otrzymaliśmy odpowiedzi na pytanie „Jak możemy uzyskać poprawną strukturę danych na serwerze?”. Ale radzę nie rozpaczać i spróbować rzucić naszą tablicę na typ obiekt:

$req->messageList->message = (object)$req->messageList->message;
W takim przypadku otrzymamy kolejną kopertę:

79871234567 Komunikat testowy 1 2013-07-21T15:00:00.26 15 79871234567 Wiadomość testowa 2 2014-08-22T16:01:10 16 79871234567 Komunikat testowy 3 2014-08-22T16:01:10 17
Przyszedł do metody Wyślij SMS obiekt ma następującą strukturę:

Object(stdClass) public "messageList" => object(stdClass) public "message" => object(stdClass) public "BOGUS" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Wiadomość testowa 1" (length=37) public "data" => string "2013-07-21T15:00:00.26" (length=22) public " type" => string "15" (length=2) 1 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Wiadomość testowa 2" (length= 37) public "data" => string "2014-08-22T16:01:10" (length=19) public "type" => string "16" (length=2) 2 => object(stdClass) public "telefon " => string "79871234567" (długość=11) public "text" => string "Wiadomość testowa 3" (length=37) public "data" => string "2014-08-22T16:01:10" (długość= 19) public "type" => string "17" (długość=2)
Jeśli chodzi o mnie, to „od zmiany miejsc terminów suma się nie zmienia” (c). Co PODROBIONY, Co Struktura Nie osiągnęliśmy jeszcze naszego celu! A żeby to osiągnąć, musimy upewnić się, że zamiast tych niezrozumiałych nazw, nasz rodzimy wiadomość. Ale jak to osiągnąć, autor jeszcze nie wie. Dlatego jedyne, co możemy zrobić, to pozbyć się dodatkowego pojemnika. Innymi słowy, upewnimy się, że zamiast wiadomość stał się PODROBIONY! Aby to zrobić, zmień obiekt w następujący sposób:

// utwórz obiekt do wysłania na serwer $req = new Request(); $msg1 = nowa wiadomość(); $msg1->telefon = "79871234567"; $msg1->text = "Wiadomość testowa 1"; $msg1->data = "2013-07-21T15:00:00.26"; $msg1->typ = 15; $msg2 = nowa wiadomość(); $msg2->telefon = "79871234567"; $msg2->text = "Wiadomość testowa 2"; $msg2->data = "2014-08-22T16:01:10"; $msg2->typ = 16; $msg3 = nowa wiadomość(); $msg3->telefon = "79871234567"; $msg3->text = "Wiadomość testowa 3"; $msg3->data = "2014-08-22T16:01:10"; $msg3->typ = 17; $req->messageList = $msg1; $req->messageList = $msg2; $req->messageList = $msg3; $req->messageList = (obiekt)$req->messageList;
Co jeśli dopisze nam szczęście i ze schematu wyjdzie prawidłowa nazwa? Aby to zrobić, spójrzmy na kopertę, która dotarła:

79871234567 Komunikat testowy 1 2013-07-21T15:00:00.26 15 79871234567 Wiadomość testowa 2 2014-08-22T16:01:10 16 79871234567 Komunikat testowy 3 2014-08-22T16:01:10 17
Tak, cud się nie wydarzył! PODROBIONY- nie wygramy! Przyszedł Wyślij SMS obiekt w tym przypadku będzie wyglądał tak:

Object(stdClass) public "messageList" => object(stdClass) public "BOGUS" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (length=11) public " text" => string "Wiadomość testowa 1" (długość=37) public "data" => string "2013-07-21T15:00:00.26" (długość=22) public "typ" => string "15" (długość =2) 1 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 2" (length=37) public "data" => string " 2014-08-22T16:01:10" (length=19) public "type" => string "16" (length=2) 2 => object(stdClass) public "phone" => string "79871234567" (length= 11) public "text" => string "Test message 3" (length=37) public "data" => string "2014-08-22T16:01:10" (length=19) public "type" => string " 17" (długość=2)
Jak mówią - „Prawie”! W tej (nieco smutnej) notatce proponuję po cichu zakończyć i wyciągnąć dla siebie kilka wniosków.

8 Wniosek

Wreszcie dotarliśmy! Zdecydujmy, co możesz teraz zrobić:
  • możesz napisać niezbędny plik WSDL dla swojej usługi sieciowej;
  • możesz bez problemu napisać własnego klienta, który może komunikować się z serwerem za pomocą protokołu SOAP;
  • możesz napisać własny serwer, który komunikuje się ze światem zewnętrznym poprzez SOAP;
  • możesz wysyłać tablice tego samego typu obiektów na serwer od swojego klienta (z pewnymi ograniczeniami).
Ponadto dokonaliśmy kilku odkryć dla siebie podczas naszych małych badań:
  • natywna klasa SoapClient nie wie, jak poprawnie serializować struktury danych tego samego typu w XML;
  • podczas serializacji tablicy do XML, tworzy dodatkowy element o nazwie Struktura;
  • podczas serializacji obiektu do XML, tworzy dodatkowy element o nazwie PODROBIONY;
  • PODROBIONY mniejsze zło niż Struktura dzięki temu, że koperta jest bardziej zwarta (w nagłówku XML koperty nie są dodawane żadne dodatkowe przestrzenie nazw);
  • niestety klasa SoapServer nie weryfikuje automatycznie danych koperty za pomocą naszego schematu XML (być może inne serwery też tego nie robią).

Co to jest MYDŁO?

SOAP oznacza Simple Object Access Protocol (Simple Object Access Protocol). Mam nadzieję, że po przeczytaniu artykułu będziesz tylko zakłopotany: „Co to za dziwne imię?”

SOAP w obecnej formie jest metodą zdalnego wywoływania procedur (RPC) przez sieć. (Tak, służy również do przekazywania dokumentów jako XML, ale na razie to pominiemy.)

Rozwiążmy to. Wyobraź sobie, że masz usługę, która zwraca notowanie giełdowe dla danego tickera (symbolu giełdowego). Wysyła dane do witryny Nasdaq i generuje pożądany wynik na podstawie zwróconego kodu HTML. Ponadto, aby umożliwić innym programistom korzystanie z niej w swoich aplikacjach, czynisz tę usługę komponentem, który znajduje informacje o cytatach za pośrednictwem Internetu. Działa świetnie, aż pewnego dnia Nasdaq zmieni układ swoich stron. Musisz przejrzeć całą logikę komponentu i wysłać aktualizacje do wszystkich programistów, którzy z niego korzystają. A oni z kolei muszą wysyłać aktualizacje do wszystkich swoich użytkowników. Jeśli dzieje się to mniej lub bardziej regularnie, możesz narobić wielu wrogów wśród innych twórców. A z programistami, jak wiesz, żarty są złe. Nie chcesz jutro wyjąć zdjęcia swojego ulubionego kota z niszczarki biurowej, prawda?

Co robić? Zobaczmy... wszystko, czego potrzebujesz, to dostarczenie jednej funkcji, która przyjmie ticker (typu string) jako dane wejściowe i zwróci notowanie giełdowe (typu float lub double). Czy nie byłoby więc łatwiej pozwolić swoim programistom w jakiś sposób wywołać tę funkcję przez Internet? Doskonały! To też dla mnie nowość, jest COM i Corba, i Java, które robią to od lat… co prawda, ale te metody nie są pozbawione wad. Zdalna konfiguracja COM nie jest trywialna. Ponadto trzeba otworzyć tyle portów w zaporze, że nie można zaoszczędzić wystarczającej ilości piwa dla administratora systemu. Tak, i musisz zapomnieć o użytkownikach wszystkich systemów operacyjnych oprócz Windows. Ale w końcu użytkownicy Linuksa również czasami interesują się wymianą.

Nie wszystko jest jednak stracone dla użytkowników Linuksa, jeśli używają DCOM, więcej tutaj: http://www.idevresource.com/com/library/res/articles/comonlinux.asp.

Nie mogę wiele powiedzieć o Corbie i Javie, więc jako ćwiczenie sugeruję czytelnikom znalezienie wad tych podejść.

SOAP to standard, który pozwala opisać takie zdalne wywołanie oraz formę, w jakiej zostanie zwrócony wynik. Dlatego musisz hostować swoją funkcję w aplikacji, która jest dostępna w sieci i odbierać połączenia w postaci pakietów SOAP. Następnie sprawdzasz poprawność danych wejściowych, uruchamiasz funkcję i zwracasz wynik w nowym pakiecie SOAP. Cały proces może przebiegać przez HTTP, więc nie musisz otwierać wielu portów w zaporze. Czy to proste?

O czym jest ten artykuł

To pierwszy z serii artykułów na temat SOAP, które piszemy w Agni Software. W tym artykule postaram się przybliżyć Ci czym jest SOAP i jak napisać aplikację komunikującą się z serwerem SOAP.

Mydło i XML

Jeśli SOAP nadal wydaje Ci się proste, dodajmy XML. Teraz, zamiast nazwy funkcji i jej parametrów, otrzymujemy dość złożoną obwiednię XML, jakby stworzoną po to, by cię zmylić. Ale nie bój się. Przed nami jeszcze więcej i musisz zobaczyć cały obraz, aby docenić złożoność SOAP.
Jeśli nie wiesz, czym jest XML, najpierw przeczytaj mój artykuł o XML tutaj: http://www.agnisoft.com/white_papers/xml_delphi.asp.

Wszystkie pakiety SOAP są w formacie XML. Co to znaczy? Zobaczmy. Spójrz na tę funkcję (Pascal):
function GetStockQuote(Symbol: string) : double; Wygląda świetnie, ale problem polega na tym, że to Pascal. Jaki jest pożytek z tej prostej definicji dla programisty Java? Lub dla kogoś, kto pracuje z VB? Potrzebujemy czegoś, co każdy może zrozumieć, nawet programiści VB. Daj im więc kod XML zawierający te same informacje (parametry, notowania giełdowe itp.). Tworzysz pakiet SOAP, który jest zasadniczo wywołaniem funkcji, opakowanym w XML, tak aby każda aplikacja na dowolnej platformie mogła go zrozumieć. Zobaczmy teraz, jak wygląda nasze wywołanie SOAP:
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">


IBM


Pouczające, prawda? MYDŁO upraszcza się na naszych oczach. Dobra, żarty na bok. Teraz postaram się wyjaśnić, jak rozumieć to wywołanie SOAP.

Odszyfrowywanie tagów

Pierwszy tag, który rzuca się w oczy to . Ten znacznik jest zewnętrznym opakowaniem pakietu SOAP, zawierającym kilka deklaracji przestrzeni nazw, które nas mało interesują, ale są bardzo ważne dla każdego języka programowania lub parsera. Przestrzenie nazw są zdefiniowane tak, aby kolejne prefiksy, takie jak „SOAP-ENV:” lub „xsd:” były akceptowane przez parser.

Następny tag to . (Pominęliśmy tag, który nie jest tutaj reprezentowany - . Nie ma go w tym konkretnym przykładzie, ale jeśli chcesz przeczytać więcej na ten temat, sprawdź specyfikację SOAP tutaj: http://www.w3.org/TR/SOAP/). Etykietka faktycznie zawiera wywołanie SOAP.

Następny tag na liście to − . Nazwa tagu, GetStockQuote, to funkcja do wywołania. Zgodnie z terminologią SOAP nazywa się to operacją. W ten sposób GetStockQuote jest operacją do wykonania. ns1 to przestrzeń nazw wskazująca na urn:xmethods-quotes w naszym przypadku.

Uwaga dodatkowa na temat przestrzeni nazw: Przestrzeń nazw umożliwia zakwalifikowanie znacznika XML. Nie można na przykład mieć dwóch zmiennych o tej samej nazwie w tej samej procedurze, ale jeśli występują w dwóch różnych procedurach, nie ma problemu. Tak więc procedura jest przestrzenią nazw, ponieważ wszystkie nazwy w niej zawarte są unikalne. Podobnie znaczniki XML są objęte zakresem przestrzeni nazw, więc mając przestrzeń nazw i nazwę znacznika, można ją jednoznacznie zidentyfikować. Zdefiniujemy przestrzeń nazw jako identyfikator URI, aby odróżnić nasz NS1 od imitatorów. W powyższym przykładzie NS1 jest aliasem wskazującym na urn:xmethods-quotes.

Zwróć także uwagę na atrybut encodingStyle — ten atrybut określa sposób serializacji wywołania SOAP.

Wewnątrz tagu zawiera parametry. W naszym najprostszym przypadku mamy tylko jeden parametr - tag . Zwróć uwagę na ten wiersz obok tagu:
xsi:type="xsd:ciąg"
W ten sposób mniej więcej definiuje typy XML. (Zauważ, jak sprytnie użyłem słowa „w przybliżeniu”, kiedy generalizuję na temat technologii, co może się zmienić po opublikowaniu artykułu.) Co to dokładnie oznacza: typ zdefiniowany w przestrzeni nazw xsi, który zauważysz, jest zdefiniowany w tagu – xsd:ciąg. A to z kolei jest ciągiem znaków zdefiniowanym w przestrzeni nazw xsd, ponownie zdefiniowanym wcześniej. (Jestem pewien, że prawnicy byliby zachwyceni tym wszystkim).

Wewnątrz tagu Na liście znajduje się „IBM”. Jest to wartość parametru symbol funkcji GetStockQuote.

W końcu jak przyzwoici ludzie zamknęliśmy wszystkie tagi.

Więc wymyśliliśmy pakiet SOAP, który definiuje wywołanie do serwera SOAP. A serwer SOAP, używając parserów XML, czerwonego przycisku i stacji kosmicznej MIR, dekoduje to wywołanie i stwierdza, że ​​potrzebujesz notowania giełdowego. Natychmiast wyszukuje wymaganą wycenę i zwraca ją w tej formie:
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>


34.5


Po rozpakowaniu koperty SOAP, oderwaniu wstążek i szeleście opakowania dowiadujemy się, że cena akcji IBM to 34,5.

Większość komercyjnych serwerów zwróciłaby znacznie więcej informacji, np. w jakiej walucie i po jakiej cenie została kupiona ostatnia akcja. Być może cena akcji byłaby bardziej precyzyjna.

Dzięki temu wiemy, czego oczekuje serwer SOAP i co zwróci. W JAKI SPOSÓB przesyłasz te informacje? Można użyć dowolnego transportu. Najbardziej podświetlony jest HTTP. Nie będę wchodził w szczegóły HTTP, dla tych, którzy nie wiedzą, to jest to, czego Twoja przeglądarka używa do komunikowania się z odwiedzanymi witrynami.

Żądane żądanie HTTP wyglądałoby mniej więcej tak:
POST /StockQuote HTTP/1.1
Host: www.stockquoteserver.com

Długość treści: nnnn
SOAPAakcja: „Niektóre URI”

Pakiet żądania mydła tutaj... Jedyną inną rzeczą, na którą należy zwrócić uwagę, jest nagłówek SOAPAction. Ten nagłówek wskazuje cel żądania i jest wymagany. Każdy serwer SOAP może mieć nieograniczoną liczbę funkcji i może użyć nagłówka SOAPAction do określenia, która funkcja jest wywoływana. Zapory sieciowe i multipleksery mogą również filtrować zawartość na podstawie tego nagłówka.

Odpowiedź SOAP z serwera HTTP będzie wyglądać tak:
HTTP/1.1 200 OK
Content-Type: tekst/xml; charset="utf-8"
Długość treści: nnnn

Pakiet odpowiedzi mydlanej tutaj... Dlaczego HTTP? Po pierwsze, administratorzy sieci nie muszą otwierać wielu osobnych portów dla połączeń SOAP... serwer WWW może spokojnie obsługiwać połączenia, ponieważ Port 80 jest zwykle otwarty dla wszystkich, którzy mogą odbierać przychodzące żądania. Kolejną zaletą jest rozszerzalność serwerów WWW za pomocą CGI, ISAPI i innych natywnych modułów. Ta rozszerzalność umożliwia napisanie modułu, który obsługuje żądania SOAP bez wpływu na inne treści WWW.

To wszystko

Mam nadzieję, że ten artykuł pomógł rzucić trochę światła na SOAP. Jeśli nadal tu jesteś i chcesz przeczytać więcej na ten temat, odwiedź stronę autora: http://www.agnisoft.com/soap

Część liryczna.

Wyobraź sobie, że wdrożyłeś lub wdrażasz pewien system, który powinien być dostępny z zewnątrz. Tych. istnieje pewien serwer, z którym musisz się komunikować. Na przykład serwer WWW.

Ten serwer może wykonywać wiele akcji, pracować z bazą danych, wykonywać żądania stron trzecich do innych serwerów, wykonywać obliczenia itp. żyć i ewentualnie rozwijać się według swojego znanego scenariusza (tj. według scenariusza twórców). Nie jest interesujące dla osoby komunikowanie się z takim serwerem, ponieważ może nie być w stanie / nie chcieć podawać pięknych stron ze zdjęciami i innymi przyjaznymi dla użytkownika treściami. Jest napisany i działa, aby działać i wydawać dane na prośby o to, nie dbając o to, aby były one czytelne dla człowieka, klient sam się nimi zajmie.

Inne systemy, które uzyskują dostęp do tego serwera, mogą już dysponować danymi otrzymanymi z tego serwera według własnego uznania - przetwarzać, gromadzić, wydawać klientom itp.

Cóż, jedną z opcji komunikacji z takimi serwerami jest SOAP. Protokół przesyłania wiadomości SOAP XML.

Część praktyczna.

Usługa sieciowa (czyli to, co zapewnia serwer i czego używają klienci) umożliwia komunikację z serwerem za pomocą dobrze ustrukturyzowanych wiadomości. Faktem jest, że serwis internetowy nie przyjmuje żadnych danych. Każda wiadomość, która nie jest zgodna z regułami, zostanie zwrócona przez usługę internetową z błędem. Błąd będzie notabene również w postaci xml z czytelną strukturą (czego nie można powiedzieć o treści wiadomości).

WSDL (język opisu usług sieci Web). Reguły, według których komponowane są komunikaty dla serwisu internetowego, są również opisane za pomocą xml i również mają przejrzystą strukturę. Tych. jeśli usługa sieciowa zapewnia możliwość wywołania metody, musi umożliwiać klientom sprawdzenie, jakie parametry tej metody są używane. Jeśli usługa sieci Web oczekuje ciągu dla metody Method1 jako parametru, a ciąg musi mieć nazwę Param1, wówczas te reguły zostaną określone w opisie usługi sieci Web.

Jako parametry można przekazywać nie tylko proste typy, ale także obiekty, kolekcje obiektów. Opis obiektu sprowadza się do opisu każdego elementu składowego obiektu. Jeżeli obiekt składa się z kilku pól, to każde pole jest opisane, jakiego ma typu, nazwy (jakie są możliwe wartości). Pola mogą być również typu złożonego i tak dalej, aż opis typów zakończy się prostymi - string, boolean, number, date... Jednak niektóre specyficzne typy mogą okazać się proste, ważne jest, aby klienci mogą zrozumieć, jakie wartości mogą być w nich zawarte.

Klientom wystarczy znajomość adresu url serwisu internetowego, wsdl zawsze będzie w pobliżu, dzięki czemu można zorientować się, jakie metody i ich parametry zapewnia ta usługa internetowa.

Jakie są zalety wszystkich tych dzwonków i gwizdków:

  • W większości systemów opis metod i typów pojawia się automatycznie. Tych. wystarczy, że programista na serwerze powie, że tę metodę można wywołać przez usługę sieciową, a opis wsdl zostanie wygenerowany automatycznie.
  • Opis o przejrzystej strukturze jest czytelny dla każdego klienta mydła. Tych. niezależnie od usługi sieciowej, klient zrozumie, jakie dane akceptuje ta usługa sieciowa. Zgodnie z tym opisem klient może zbudować własną wewnętrzną strukturę klas obiektów, tzw. bind” oraz. W efekcie programista korzystający z serwisu WWW musi napisać coś takiego (pseudokod):

    NewUser:=TSoapUser.Create("Vasya","Pupkin","admin"); mydło.DodajUżytkownik(NowyUżytkownik);

  • Automatyczna walidacja.

    • walidacja XML. xml musi być dobrze sformułowany. nieprawidłowy xml - natychmiast błąd klienta, niech się zorientuje.
    • walidacja schematu. xml musi mieć określoną strukturę. xml nie pasuje do schematu - od razu błąd do klienta, niech to rozgryzie.
    • sprawdzanie poprawności danych jest przeprowadzane przez serwer mydła, tak aby typy danych i ograniczenia były zgodne z opisem.
  • Autoryzacja i uwierzytelnianie mogą być realizowane osobną metodą. natywnie. lub za pomocą autoryzacji http.
  • Usługi sieciowe mogą działać zarówno na protokole mydlanym, jak i na http, czyli poprzez żądania pobierania. Oznacza to, że jeśli jako parametry używane są proste dane (bez struktury), możesz po prostu wywołać zwykły get www.site.com/users.asmx/GetUser?Name=Vasia lub post. Jednak nie zawsze i wszędzie.
  • ... zobacz wikipedię

Jest też wiele wad:

  • Nierozsądnie duży rozmiar wiadomości. Cóż, tutaj sama natura xml jest taka, że ​​format jest zbędny, im więcej tagów, tym więcej bezużytecznych informacji. Plus mydło zwiększa jego redundancję. W przypadku systemów intranetowych problem ruchu jest mniej dotkliwy niż w przypadku Internetu, więc mydło dla sieci lokalnych jest bardziej pożądane, w szczególności Sharepoint ma mydlaną usługę internetową, z którą można komunikować się z powodzeniem (z pewnymi ograniczeniami).
  • Automatyczna zmiana opisu usługi sieciowej może zepsuć wszystkich klientów. Cóż, jest jak z każdym systemem, więc jeśli wsteczna kompatybilność ze starymi metodami nie jest obsługiwana, wszystko odpadnie...
  • Nie minus, ale wada. Wszystkie akcje wywołania metody muszą być niepodzielne. Na przykład podczas pracy z subd możemy rozpocząć transakcję, wykonać kilka zapytań, a następnie wycofać lub zatwierdzić. Nie ma transakcji na mydle. Jedna prośba, jedna odpowiedź, rozmowa się skończyła.
  • Zajmowanie się opisem tego co jest po stronie serwera (czy wszystko jest przeze mnie opisane poprawnie?), co jest na kliencie (co mi tu napisano?) może być dość trudne. Kilka razy musiałem zajmować się stroną klienta i przekonywać programistę serwera, że ​​niewłaściwie opisał dane, ale w ogóle nic w nich nie mógł zrozumieć, bo automatyczne generowanie i on jakby nie powinien, to kwestia oprogramowania. A błąd był naturalnie w kodzie metody, programista po prostu go nie widział.
  • Praktyka pokazuje, że twórcy usług internetowych są strasznie daleko od osób korzystających z tych usług internetowych. W odpowiedzi na każde żądanie (ważne z zewnątrz) może pojawić się niezrozumiały błąd „Błąd 5. Wszystko jest złe”. Wszystko zależy od sumienia twórców :)
  • Na pewno nic nie pamiętałem...

Przykładem jest otwarta usługa internetowa belavia:

  • http://86.57.245.235/TimeTable/Service.asmx - punkt wejścia, jest też tekstowy opis metod dla zewnętrznych programistów.
  • http://86.57.245.235/TimeTable/Service.asmx?WSDL - wsdl opis metod i typów odbieranych i zwracanych danych.
  • http://86.57.245.235/TimeTable/Service.asmx?op=GetAirportsList - opis konkretnej metody z przykładem typu żądania xml i odpowiedzi xml.

Możesz ręcznie utworzyć i wysłać żądanie, takie jak:

POST /TimeTable/Service.asmx HTTP/1.1 Host: 86.57.245.235 Content-Type: text/xml; charset=utf-8 Content-Length: length SOAPAction: "http://webservices.belavia.by/GetAirportsList" en

odpowiedź będzie brzmiała:

HTTP/1.1 200 OK Data: Pon, 30 września 2013 00:06:44 GMT Serwer: Microsoft-IIS/6.0 X-Powered-By: ASP.NET X-AspNet-Version: 4.0.30319 Kontrola pamięci podręcznej: prywatna, max -age=0 Content-Type: tekst/xml; charset=utf-8 Długość treści: 2940

ZY Wcześniej została otwarta usługa internetowa Aeroflot, ale po dodaniu przez 1C obsługi mydła w 8ku, grupa beta testerów 1c pomyślnie ją zainstalowała. Teraz coś się tam zmieniło (nie znam adresu, możesz poszukać, jeśli jesteś zainteresowany).
Zastrzeżenie ZZY. Przemawiał na poziomie gospodarstwa domowego. Możesz się napić.

Ogólnie rzecz biorąc, obecnie istnieją standardowe protokoły wymiany danych XML:

  • XML-RPC- przekazujesz pakiet i określasz, jaką metodą na serwerze chcesz się połączyć.
  • RESZTA- na serwerze znajdują się obiekty. Każdy obiekt charakteryzuje się jakimś identyfikatorem. Każdy element ma swój własny adres URL. Z dowolnym elementem możesz: wstawić, usunąć, zaktualizować, wybrać. Po prostu wysyłasz żądane żądanie do serwera (na przykład wstawiasz taki a taki element). Wymiana klient-serwer opiera się na JSON lub XML.

SOAP jest oparty na RPC (Service Oriented Architecture, zbiór luźno powiązanych usług, które współdziałają ze sobą). Główną zaletą RPC jest niewielka ilość zasobów sieciowych (punktów wejścia) i wiele związanych z tym metod. Pomimo tej przewagi RPC jest przestarzałym protokołem, który ma wiele wad:

  • Nie można sprawdzić poprawności komunikatu XML-RPC. Stary protokół powstał zanim schematy (metody walidacji danych) zostały ujednolicone w XML. Tych. serwer przyjmuje żądania, musi upewnić się, że te żądania są dla niego, a dane nie są niespójne. W XML-RPC typy danych są deklarowane w tym celu, ale jest to sprawdzenie typu danych, a spójność danych nie jest sprawdzana (otrzymałeś strukturę ze wszystkimi niezbędnymi parametrami).
  • Nie możesz tworzyć połączonych wiadomości.
  • Nie można używać przestrzeni i czasu (pojawiło się po utworzeniu RPC).
  • Nie możesz rozwinąć wiadomości, tj. dodaj dodatkowe informacje.

Wszystkie te niedociągnięcia zostały rozwiązane w XML Schema. Jest to branżowy standard opisu dokumentu XML. Tych. jest to sposób modelowania dowolnych danych. Schemat XML może opisywać model (relacje między elementami i atrybutami oraz ich strukturą), typy danych (charakteryzuje typy danych) oraz słownictwo (nazwy elementów i atrybutów).

Bazując na wszystkich niedociągnięciach XML-RPC, stworzyli protokół SOAP.

MYDŁO(Simle Object Access Protocol) - protokół dostępu do obiektu (punktu wejścia). Dziś jest to główny standard branżowy do tworzenia aplikacji rozproszonych.

Jest rozszerzeniem języka XML-RPC. Tych. zbudowany jest na zasadzie: 1 punkt wejścia i dowolne metody. Sam protokół w zakresie transportu (jak przesyłać dane) daje szeroki wybór: SMTP, FTP, HTTP, MSMQ.

SOAP jest sercem implementacji XML Web Services (XML Web Services). Minusem SOAP jest to, że trudno się go nauczyć.

SOAP opiera się na wymianie komunikatów między klientem a serwerem (synchronicznie i asynchronicznie). Każda wiadomość zawiera informacje o danych (jakie dane są przesyłane/odbierane). SOAP z góry opisuje całą strukturę wiadomości za pomocą schematów XML: co powinno być w wiadomości, jak zostanie przekazane. Dzięki temu bez znajomości serwera można zrozumieć, co się tam dzieje, a serwer może sprawdzić, czy ta wiadomość jest dla niego.

Schemat XML

Celem schematu jest opisanie struktury danych, tj. co mamy. Wszystkie dane są podzielone na typy proste i złożone (skalary i struktury). Typ prosty (string, number, boolean, date) nigdy nie będzie zawierał niczego w środku. Struktura (obiekt) może zawierać właściwości.

Podstawowe operacje SOAP

  • Nie tylko prosta wymiana informacji klient-serwer. Ale automatyczne rozpoznanie serwera i wyszukiwanie tego serwera, czyli klient może nawet nie wiedzieć nic o serwerze. Tych. klient najpierw szuka serwera, znajduje odpowiednie usługi, rozumie jakie są tam metody, co jest na serwerze i wykonuje do niego wywołanie.
  • Serwer publikuje swoje informacje (lokalizacja, jakie metody obsługuje), aby klient mógł znaleźć ten serwer. Publikacja odbywa się w katalogu UDDI.

Struktura komunikatów SOAP:

  • Koperta SOAP (koperta) — zawiera całą wiadomość. Składa się z nagłówka i treści.
  • SOAP Header (header) - dodatkowe informacje (np. autoryzacja).
  • SOAP Body (body) - sama wiadomość.
  • SOAP Fault (błąd) - sposób na przeniesienie błędów z serwera do klienta.

WSDL

WSDL(Język opisu usług sieci Web) — Język opisu usług sieci Web. Używany w SOAP. Jest to rodzaj dokumentu, który opisuje wszystko: jakie przestrzenie nazw zostały użyte, jakie schematy danych zostały użyte, jakich typów wiadomości serwer oczekuje od klienta, jakie koperty należą do jakiej metody, jakie metody ogólnie istnieją, na jaki adres wysłać, itp. W rzeczywistości WSDL jest usługą sieciową. Wystarczy, że klient zapozna się z treścią tego dokumentu, o serwerze wie już wszystko.

Każdy serwer powinien opublikować WSDL.

WSDL składa się z bloków:

  • Definicja samej usługi, czyli punkt wejścia, port jest określony.
  • Format metody. Punkt wejścia jest powiązany z operacjami, tj. jakie metody obsługuje. Wskaż rodzaj połączenia, metodę transmisji. Wewnątrz każdej metody znajduje się wyjaśnienie - w jakiej formie przesyłane są dane - w postaci SOAP.
  • Metody powiązania z wiadomością.
  • Opis samych wiadomości.

Zastrzeżenie:Na ten temat napisano wiele artykułów i, jak oczywiście zgadłeś, jest to kolejny. Być może nauczysz się z niego czegoś nowego, ale nic ściśle tajnego, czego nie mógłbyś samodzielnie wygooglować, nie jest tutaj opisane. Tylko notatki z osobistych doświadczeń.

Wstęp

Rozważymy tylko sytuację, gdy istnieje serwis internetowy innej firmy, a zadaniem jest nawiązanie wymiany danych.

Struktura serwisu jest opisana w pliku WSDL(ang. Web Services Description Language)

Do pliku najczęściej uzyskuje się dostęp za pośrednictwem łącza, w którym znajduje się punkt wejścia do samej usługi sieciowej. Pisałem „najczęściej”, bo są wyjątki. Na przykład usługa sieci Web oparta na SAP nie publikuje pliku wsdl i można ją pobrać tylko z samej aplikacji.

I tak mamy opis serwisu WWW, login, hasło. Połączmy się.

// Zdefiniuj ustawienia adresu URL ServiceNamespace = "http://Somesite.ru"; Nazwa użytkownika = "Użytkownik Testowy"; Hasło = "q1w2e3"; LokalizacjaWSDL = "https://Somesite.ru/WebService/Some?wsdl"; ServiceName = "JakaśNazwaUsługi"; ConnectionPointName = "SomeService_Port"; // Utwórz połączenie SSL = New SecureConnectionOpenSSL(); WSDefinition = Nowy WSDefinition(LokalizacjaWSDL,SSL); WSProxy = Nowy WSProxy(WSDefinition, adres URL przestrzeni nazw usług, nazwa usługi, nazwa punktu połączenia, SSL); WSProxy.Użytkownik = Nazwa użytkownika; WSProxy.Password = Hasło;

Doskonały! Połączyliśmy się z serwisem internetowym! W teorii jest to podstawa każdej opcji wymiany, ponieważ pozwala na tworzenie obiekt struktury danych oparty na wsdl, a praca z takim obiektem to przyjemność.

Rozważ XML, który daje nam SoapUI

357 121212 M 19900111 Mercedes GLS Audi TT

Teraz opiszmy to programowo

// Utwórz obiekt i wypełnij go danymi OwnXDTOFactory = WSDefinition.XDTOFactory; RootType = OwnFactoryXDTO.Type(URLServiceNamespace, "ZŁOŻENIE"); RootObject = WłasnaFabrykaXDTO.Create(RootType); RootObject.ID = "4356"; ClientType = OwnFactoryXDTO.Type(URLServiceNamespace, "CUSTOMER"); ObiektKlienta = WłasnaFabrykaXDTO.Create(TypKlienta); ClientObject.CLIENT_ID = "121212"; KlientObiekt.SEX = "M"; // F - kobieta, M - mężczyzna ClientObject.CLIENT_BIRTHDAY = "19900111"; // Samochody klientów AutoType = CustomFactoryXDTO.Type(URLServiceNamespace, "CARS"); AutoObject = WłasnaFabrykaXDTO.Create(AutoTyp); AutoObject.CLASS = "Mercedes"; AutoObject.MODEL = "GLS"; ObiektKlienta.SAMOCHODY.Add(AutoObiekt); AutoObject = WłasnaFabrykaXDTO.Create(AutoTyp); AutoObject.CLASS = "Audi"; AutoObject.MODEL = "TT"; ObiektKlienta.SAMOCHODY.Add(AutoObiekt); Obiekt główny.KLIENT.Dodaj(ObiektKlienta);

Dane zakończone pomyślnie. Teraz musimy je wysłać.

W tym momencie pojawia się wiele niuansów. Spróbujmy rozważyć każdy.

Przepis 1. Wysyłanie całego obiektu XDTO

Wynik = WSProxy.AddCustomers(RootObject);

Pozostaje tylko przetworzyć wynik, który usługa nam zwróciła i to wszystko. Zgadzam się, że jest to bardzo wygodne!

Ale w praktyce nie zawsze tak jest. Na przykład 1c nie radzi sobie z prefiksami niektórych znaczników wewnątrz xml, gdy przestrzeń nazw znacznika głównego różni się od przestrzeni nazw znaczników podrzędnych. W takich przypadkach mydło trzeba zbierać ręcznie. Miałem też do czynienia z usługami sieciowymi, które jako parametr oczekują czystego xml. Szaleństwo, ale nadal nie jest to trudne do zrobienia.

Przepis 2. Wysyłanie czystego xml jako parametru

XMLRecordParameters = NewXMLRecordParameters("UTF-8", "1.0", Prawda); MójXML = Nowy XMLWriter; MójXML.SetString(XMLRecordParameters); MyXML.WriteDeclarationXML(); CustomXDTOFactory.WriteXML(MyXML, RootObject); StringXML = Mój XML.Zamknij(); If DeleteNamespaceDescription Then AttemptFirstTagInString = StrGetString(XMLString,2); NazwaTagKorzeń = ObiektKorzeń.Typ().Nazwa; XMLString = StrReplace(XMLString, FirstTagInString, "<"+ИмяКорневогоТэга+">"); Wyjątek //ErrorDescription() EndTry; EndIf; Wynik = WSProxy.AddCustomers(XML String);

Jeśli nie usuniesz przestrzeni nazw, które 1s dodaje domyślnie, oznacza to, że jest to więcej niż tylko 5 wierszy kodu. W większości przypadków opakowuję transformację XML w funkcję, ponieważ zwykle wywołujemy więcej niż jedną metodę.

Przepis 3. Wyślij przez natywne żądanie HTTP.

Ciąg SOAP = " | | |" +StringXML+ " | |"; // Opis nagłówków żądań HTTP Headers = New Match; Headers.Insert("Content-Type", "text/xml;charset=UTF-8"); Headers.Insert("SOAPAction", "http:// sap .com/xi/WebService/soap1.1"); Headers.Insert("Authorization", "Basic "+GetBase64AuthorizationHeader(Username, Password)); // UWAGA!!! // Nie można programowo wypełnić następujących nagłówków, ponieważ prowadzi to do błędu // Platforma wypełni je poprawnie //Headers.Insert("Accept-Encoding", "gzip,deflate"); //Headers.Insert("Content-Length", Format(StringLength( SOAP String)," HG=")); // długość wiadomości //Headers.Insert("Host", "Somesite.ru:8001"); //Headers.Insert("Połączenie", "Keep-Alive") ; //Nagłówki. Insert("User-Agent", "Apache-HttpClient/4.1.1 (java 1.5)"); // Połącz z witryną. Connection = New HTTPConnection("Somesite.ru/WebService/Some", Username, Password,SSL, false); // Adres musi być bez https:// // Pobierz tekst strony głównej za pomocą żądania POST. c = Nowe żądanie HTTP("/GetCustomer", nagłówki); HTTPRequest.SetBodyFromString(SOAPString); Wynik = Connection.CallHTTPMethod("POST", HTTPRequest);

W tej opcji będziemy musieli ręcznie zbudować mydło. W skrócie, po prostu owijamy xml z przepisu 2 w opakowanie mydła, gdzie w zależności od wymagań serwisu internetowego możemy zmienić nasze mydło do woli.

Następnie opisujemy nagłówki zgodnie z dokumentacją. Niektóre usługi z łatwością przegryzą nasze żądanie bez nagłówków, tutaj musisz przyjrzeć się konkretnemu przypadkowi. Jeśli nie wiesz, jakie nagłówki przepisać, najłatwiej jest podejrzeć żądanie w SoapUI, przechodząc do zakładki RAW.

Funkcja pobierania ciągu Base64 wygląda tak (podglądanie):

Funkcja GetBase64AuthorizationHeader(nazwa użytkownika, hasło) FileEncoding = TextEncoding.UTF8; PlikTymczasowy = PobierzNazwęPlikuTymczasowego(); Rekord = Nowy TextWrite (Plik Tymczasowy, Kodowanie Plików); Write.Write(Nazwa użytkownika+":"+hasło); Rekord.Zamknij(); BinData = New BinaryData (TempFile); Wynik = Base64String(DvData); UsuńPliki (Plik Szablonowy); Wynik = Średnia(Wynik;5); Zwróć wynik; Funkcje końcowe

Jest ważny punkt. Podczas pracy z HTTPConnection określ adres bez określania protokołów „http://” i „https://”, w przeciwnym razie ryzykujesz marnowanie czasu na szukanie nieoczywistego błędu.

Przepis 4. Wysyłanie przez WinHttpRequest

WinHttp = Nowy COMObject("WinHttp.WinHttpRequest.5.1"); WinHttp.Option(2,"UTF-8"); Opcja WinHttp(4, 13056); //intSslErrorIgnoreFlag WinHttp.Option(6, true); //blnEnableRedirects WinHttp.Option(12, true); //blnEnableHttpsToHttpRedirects WinHttp.Open("POST", "https://Somesite.ru/WebService/Some/GetCustomer", 0); WinHttp.SetRequestHeader("Typ treści", "tekst/xml"); WinHttp.SetCredentials (nazwa użytkownika, hasło, 0); WinHttp.Send (ciąg SOAP); WinHttp. WaitForResponse(15); XMLResponse = WinHttp.ResponseText();

Tutaj w zasadzie to samo, co w poprzedniej wersji, ale pracujemy z obiektem COMObject. Określamy w pełni ciąg połączenia wraz z protokołem. Na szczególną uwagę zasługują tylko flagi ignorowania błędów w certyfikatach SSL. Są potrzebne, jeśli pracujemy po SSL, ale bez konkretnego certyfikatu, ponieważ nie ma możliwości utworzenia nowego bezpiecznego połączenia w tej opcji (lub nie wiem jak). Reszta mechanizmu jest podobna do poprzedniego.

Ponadto, oprócz „WinHttp.WinHttpRequest.5.1”, możesz użyć „Microsoft.XMLHTTP”, „Msxml2.XMLHTTP”, „Msxml2.XMLHTTP.3.0”, „Msxml2.XMLHTTP.6.0”, jeśli nagle nie zajmie wyłączony na WinHttp. Metody są prawie takie same, różni się tylko liczba parametrów. Podejrzewam, że jedna z tych opcji jest połączona z obiektem 1c HTTPRequest.

W tej chwili są to wszystkie przepisy, które mam. Jeśli trafię na nowe, na pewno uzupełnię artykuł.

Przetwarzanie wyników

W przepisie 1 najczęściej otrzymujemy gotowy obiekt XDTO i pracujemy z nim jako strukturą. We wszystkich innych przypadkach możesz przekonwertować odpowiedź xml na XDTO

If Result.StatusCode = 200 Then XMLReader = Nowy XMLReader; ReadingXML.SetString(Result.GetBodyAsString()); ResponseObject = Własna FabrykaXDTO.ReadXML(ReadingXML); Report(ObiektOdpowiedź.Body.Odpowiedź.RESPONSE_ID); Raport(ObiektOdpowiedź.Body.Odpowiedź.RESPONSE_TEXT); EndIf;

Tutaj wszystko jest proste.

Zamiast konkluzji

1. Rozpocznij pracę z usługami internetowymi za pomocą programu SoapUI. Jest przeznaczony do takiej pracy i pozwoli szybko zrozumieć, jak działa konkretna usługa. Jest artykuł do nauczenia

2. Jeśli wymieniasz się z usługą za pośrednictwem niezabezpieczonego kanału http i pojawia się pytanie, co dokładnie 1s wysyła w Twoich wiadomościach, możesz użyć snifferów ruchu, takich jak Wireshark, Fiddler i innych. Problem występuje tylko wtedy, gdy używasz połączenia SSL.

3. Jeśli jednak serwis WWW komunikuje się przez https, to instalujemy serwer Nginx na zdalnej maszynie (dowolnej, co najważniejsze, nie własnej), z którą się skontaktujemy, a ona z kolei wszystko spakuje https i wyślij we właściwe miejsce ( odwrotny serwer proxy ) i dodaj do standardowej konfiguracji:

Serwer ( nasłuchuj 0.0.0.0:8080; nazwa_serwera MyServer; lokalizacja ~ .* ( proxy_pass https://Somesite.ru:8001; proxy_set_header Host $host; proxy_set_header Autoryzacja "Podstawowe "; proxy_pass_header Autoryzacja; ) )

5. Jeżeli uwierzytelnianie wiąże się z wykorzystaniem plików Cookies, to znaleziono następujące:

PS Jeśli masz pytania, sugestie usprawnienia kodu, masz własne przepisy różniące się od opisanych, znajdziesz błędy lub uważasz, że autor się „myli” i „nie należy w 1s”, to pisz komentarze i porozmawiamy wszystko.