Protocol SOAP și servicii web. Ce este WSDL, SOAP și REST

  • Tutorial

Salutare tuturor!
S-a întâmplat că recent am început să dezvolt servicii web. Dar astăzi subiectul nu este despre mine, ci despre cum putem scrie propriul nostru serviciu web XML bazat pe protocolul SOAP 1.2.

Sper că după ce ai citit subiectul vei putea:

  • scrieți propria implementare de server a unei aplicații web;
  • scrieți propria implementare client a unei aplicații web;
  • scrieți propria descriere a serviciului web (WSDL);
  • trimite matricele client de același tip de date către server.
După cum probabil ați ghicit, toată magia se va face folosind PHP și clasele încorporate SoapClient și SoapServer. Iepurele nostru va fi un serviciu de trimitere de mesaje SMS.

1 Declarație de problemă

1.1 Limite

La început, îmi propun să ne ocupăm de rezultatul pe care îl vom obține la finalul subiectului. După cum am anunțat mai sus, vom scrie un serviciu de trimitere de mesaje SMS și, mai precis, vom primi mesaje din diferite surse prin protocolul SOAP. După care, vom lua în considerare sub ce formă vin pe server. Procesul de a pune în coadă mesajele pentru trimiterea ulterioară către furnizor, din păcate, depășește scopul acestei postări din mai multe motive.

1.2 Ce date vom schimba?

Super, ne-am hotărât limitele! Următorul pas care trebuie făcut este să decidem ce date vom schimba între server și client. Pe acest subiect, vă sugerez să nu despărțiți părul prea mult timp și să răspundeți imediat la întrebările principale:
  • Ce date minime trebuie trimise către server pentru a trimite un mesaj SMS unui abonat?
  • Ce date minime trebuie trimise de la server pentru a satisface nevoile clientului?
Ceva îmi spune că pentru asta trebuie să trimiți următoarele:
  • numărul de telefon mobil și
  • textul mesajului SMS.
În principiu, aceste două caracteristici sunt suficiente pentru a trimite, dar îmi imaginez imediat cazul unui SMS cu felicitări de ziua de naștere care vă vine la ora 3 dimineața, sau 4! În acest moment, voi fi foarte recunoscător tuturor pentru că nu au uitat de mine! Prin urmare, vom trimite și către server și
  • data trimiterii mesajului SMS.
Următorul lucru pe care aș dori să-l trimit pe server este:
  • Tipul mesajului.
Acest parametru nu este obligatoriu, dar ne poate fi foarte util dacă trebuie să îi spunem rapid șefului câți dintre clienții noștri ne-am „încântat” de știrile noastre și, de asemenea, să tragem câteva statistici frumoase pe această temă.

Și totuși, am uitat ceva! Dacă reflectăm puțin mai mult, este de remarcat faptul că clientul poate trimite fie un mesaj SMS, fie câteva dintre ele la server la un moment dat. Cu alte cuvinte, un pachet de date poate conține de la unu la infinit mesaje.

Drept urmare, obținem că pentru a trimite un mesaj SMS avem nevoie de următoarele date:

  • Numar de telefon mobil,
  • text mesaj SMS,
  • ora trimiterii mesajului SMS către abonat,
  • tipul mesajului.

Am răspuns la prima întrebare, acum trebuie să răspundem la a doua întrebare. Și poate îmi voi permite să fac un pic de încurcătură. Prin urmare, de pe server vom trimite doar date booleene, a căror semnificație are următoarea semnificație:

  • TRUE – pachetul a ajuns cu succes la server, a trecut autentificarea și a fost în coada de așteptare pentru a fi trimis la furnizorul de SMS-uri
  • FALSE – în toate celelalte cazuri

Aceasta încheie descrierea enunțului problemei! Și, în sfârșit, să trecem la partea distractivă - să ne dăm seama ce fel de fiară ciudată este acest SAPUN!

2 Ce este SAPUNUL?

În general, inițial nu am plănuit să scriu nimic despre ce este SOAP și am vrut să mă limitez la link-uri către site-ul w3.org cu specificațiile necesare, precum și link-uri către Wikipedia. Dar la final am decis să scriu o scurtă notă despre acest protocol.

Și îmi voi începe povestea cu faptul că acest protocol de schimb de date aparține unui subset de protocoale bazate pe așa-numita paradigmă RPC (Remote Procedure Call), al cărei antipod este REST (Representational State Transfer). Puteți citi mai multe despre acest lucru pe Wikipedia, linkurile către articole sunt la sfârșitul subiectului. Din aceste articole, trebuie să înțelegem următoarele: „Abordarea RPC permite utilizarea unui număr mic de resurse de rețea cu un număr mare de metode și un protocol complex. Cu abordarea REST, numărul de metode și complexitatea protocolului sunt strict limitate, ceea ce înseamnă că numărul de resurse individuale poate fi mare.” Adică, în raport cu noi, asta înseamnă că în cazul abordării RPC pe site va exista întotdeauna o intrare (link) către serviciu și ce procedură să apelăm pentru a procesa datele primite pe care le transferăm împreună cu datele, în timp ce cu abordarea REST în site-ul nostru are multe intrări (link-uri), fiecare dintre acestea acceptând și procesând doar anumite date. Dacă cineva care citește știe cum să explice diferența dintre aceste abordări și mai simplu, nu uitați să scrieți în comentarii!

Următorul lucru pe care trebuie să-l știm despre SOAP este că acest protocol folosește același XML ca transport, ceea ce, pe de o parte, este foarte bun, deoarece Arsenalul nostru include imediat întreaga putere a unui teanc de tehnologii bazate pe acest limbaj de marcare, și anume XML-Schema - un limbaj pentru descrierea structurii unui document XML (mulțumesc Wikipedia!), care permite validarea automată a datelor primite de server. de la clienti.

Și așa, acum știm că SOAP este un protocol folosit pentru a implementa apeluri de procedură de la distanță și folosește XML ca transport! Dacă citiți articolul de pe Wikipedia, puteți afla și de acolo că poate fi folosit peste orice protocol la nivel de aplicație și nu doar în combinație cu HTTP (din păcate, în acest subiect vom lua în considerare doar SOAP peste HTTP). Și știi ce îmi place cel mai mult la toate astea? Dacă nu există ghiciri, atunci voi da un indiciu - SAPUN!... Încă nu ghiciți?... Ești sigur că ai citit articolul de pe Wikipedia?... În general, nu te voi mai tortura. Prin urmare, voi merge direct la răspunsul: „SOAP (din engleză Simple Object Access Protocol - simplu protocol acces la obiecte; până la specificația 1.2)". Cel mai remarcabil lucru la această linie este scrisul cu caractere cursive! Nu știu ce concluzii ați tras din toate acestea, dar văd următoarele - deoarece acest protocol nu poate fi în niciun fel numit „simplu” (și se pare că chiar și w3 este de acord cu asta), atunci de la versiunea 1.2 a încetat cumva să fie decriptat ! Și a devenit cunoscut sub numele de SOAP, doar SOAP, punct.

Ei bine, vă rog să mă scuzați, am fost puțin deturnat. După cum am scris mai devreme, XML este folosit ca transport, iar pachetele care călătoresc între client și server se numesc plicuri SOAP. Dacă luați în considerare structura generală a plicului, vi se va părea foarte familiar, deoarece... seamănă cu structura unei pagini HTML. Are o secțiune principală - Învălui, care include secțiuni AntetȘi Corp, sau Vina. ÎN Corp datele sunt transmise și este o secțiune obligatorie a plicului, în timp ce Antet este opțională. ÎN Antet pot fi transmise autorizarea sau orice alte date care nu au legătură directă cu datele de intrare ale procedurilor serviciului web. Despre Vina nu este nimic special de spus, cu excepția faptului că vine la client de pe server în cazul oricăror erori.

Aici se termină povestea mea de revizuire despre protocolul SOAP (ne vom uita la plicurile în sine și la structura lor mai detaliat când clientul și serverul nostru vor învăța în sfârșit să le ruleze unul pe celălalt) și începe una nouă - despre companionul SOAP numit WSDL(Limbajul de descriere a serviciilor web). Da, da, acesta este exact lucrul care ne sperie pe cei mai mulți dintre noi chiar și de a încerca să implementăm API-ul nostru pe acest protocol. Ca rezultat, de obicei ne reinventăm roata cu JSON ca transport. Deci, ce este WSDL? WSDL este un limbaj pentru descrierea serviciilor web și accesarea acestora, bazat pe limbajul XML (c) Wikipedia. Dacă această definiție nu vă explică întregul sens sacru al acestei tehnologii, atunci voi încerca să o descriu cu propriile mele cuvinte!

WSDL este conceput pentru a permite clienților noștri să comunice în mod normal cu serverul. Pentru a face acest lucru, fișierul cu extensia „*.wsdl” descrie următoarele informații:

  • Ce spații de nume au fost folosite?
  • Ce scheme de date au fost folosite?
  • Ce tipuri de mesaje așteaptă serviciul web de la clienți?
  • Ce date aparțin căror proceduri de servicii web,
  • Ce proceduri conține serviciul web?
  • Cum ar trebui clientul să apeleze procedurile serviciului web,
  • La ce adresă trebuie trimise apelurile clienților?
După cum puteți vedea, acest fișier este întregul serviciu web. Specificând adresa fișierului WSDL în client, vom ști totul despre orice serviciu web! Drept urmare, nu trebuie să știm absolut nimic despre locul în care se află serviciul web în sine. Tot ce trebuie să știți este locația fișierului său WSDL! Vom afla în curând că SOAP nu este atât de înfricoșător pe cât spun proverbele rusești.

3 Introducere în XML-Schema

Acum știm multe despre ce este SOAP, ce este în el și avem o privire de ansamblu asupra stivei de tehnologie care îl înconjoară. Întrucât, în primul rând, SOAP este o metodă de interacțiune între un client și un server, iar limbajul de markup XML este folosit ca transport pentru acesta, în această secțiune vom înțelege puțin despre modul în care are loc validarea automată a datelor folosind scheme XML.

Sarcina principală a diagramei este de a descrie structura datelor pe care urmează să le procesăm. Toate datele din schemele XML sunt împărțite în simplu(scalar) și complex(structuri) tipuri. Tipurile simple includ următoarele tipuri:

  • linia,
  • număr,
  • valoare booleană,
  • data de.
Ceva foarte simplu care nu are extensii în interior. Antipodul lor este de tipuri complexe complexe. Cel mai simplu exemplu de tip complex care vine în minte tuturor sunt obiectele. De exemplu, o carte. Cartea constă din proprietăți: autor, Nume, Preț, numărul ISBN etc. Și aceste proprietăți, la rândul lor, pot fi fie tipuri simple, fie complexe. Și sarcina schemei XML este de a descrie acest lucru.

Vă sugerez să nu mergeți departe și să scrieți o schemă XML pentru mesajul nostru SMS! Mai jos este descrierea xml a mesajului SMS:

71239876543 Mesajul de testare 20-07-2013T12:00:00 12
Diagrama noastră de tip complex va arăta astfel:


Această intrare arată după cum urmează: Avem o variabilă " mesaj" tip " Mesaj„și există un tip complex numit „ Mesaj", care constă dintr-un set secvenţial de elemente" telefon" tip şir, « text" tip şir, « Data" tip dateTime, « tip" tip zecimal. Aceste tipuri sunt simple și sunt deja definite în descrierea schemei. Felicitări! Tocmai am scris prima noastră schemă XML!

Cred că sensul elementelor " element" Și " complexType„Totul a devenit mai mult sau mai puțin clar pentru tine, așa că nu ne vom mai concentra asupra lor și hai să trecem direct la elementul compozitor” secvenţă" Când folosim elementul compozitor " secvenţă„Vă informăm că elementele incluse în acesta trebuie să fie întotdeauna amplasate în ordinea specificată în diagramă, iar toate sunt obligatorii. Dar nu dispera! Mai există două elemente de compoziție în schemele XML: " alegere" Și " toate" Compozitor" alegere" anunță că trebuie să existe unul dintre elementele enumerate în acesta, iar compozitorul " toate» – orice combinație a elementelor enumerate.

După cum vă amintiți, în prima secțiune a subiectului am convenit că de la unul la infinit mesajele SMS pot fi transmise într-un pachet. Prin urmare, îmi propun să înțelegem cum sunt declarate astfel de date în schema XML. Structura generală a pachetului ar putea arăta astfel:

71239876543 Mesajul de testare 1 20-07-2013T12:00:00 12 71239876543 Mesajul de testare N 20-07-2013T12:00:00 12
Diagrama pentru un astfel de tip complex va arăta astfel:


Primul bloc conține declarația familiară de tip complex „ Mesaj" Dacă ați observat, atunci în fiecare tip simplu inclus în " Mesaj", au fost adăugate noi atribute de clarificare" minApare" Și " maxApare" După cum ați putea ghici din nume, primul ( minApare) indică faptul că această secvență trebuie să conțină cel puțin un element de tip „ telefon», « text», « Data" Și " tip", în timp ce următorul ( maxApare) atributul ne declară că există cel mult un astfel de element în secvența noastră. Ca rezultat, atunci când scriem propriile noastre scheme pentru orice date, ni se oferă cea mai largă alegere în ceea ce privește modul de configurare a acestora!

Al doilea bloc al diagramei declară elementul " listă de mesaje" tip " Listă de mesaje" Este clar că " Listă de mesaje" este un tip complex care conține cel puțin un element " mesaj„, dar numărul maxim de astfel de elemente nu este limitat!

4 Scrieți WSDL

Vă amintiți că WSDL este serviciul nostru web? Sper să vă amintiți! Pe măsură ce îl scriem, micul nostru serviciu web va rula pe el. Prin urmare, vă sugerez să nu vă încurcați.

În general, pentru ca totul să funcționeze corect pentru noi, trebuie să transferăm clientului un fișier WSDL cu tipul MIME corect. Pentru a face acest lucru, trebuie să configurați serverul dvs. web în consecință, și anume, setați tipul MIME pentru fișierele cu extensia „*.wsdl” la următoarea linie:

Aplicație/wsdl+xml
Dar, în practică, de obicei trimiteam antetul HTTP prin PHP " text/xml»:

Antet ("Content-Type: text/xml; charset=utf-8");
și totul a funcționat excelent!

Vreau să vă avertizez imediat că serviciul nostru web simplu va avea o descriere destul de impresionantă, așa că nu vă alarmați, pentru că... Majoritatea textului este apă obligatorie și, după ce l-a scris o singură dată, îl poți copia constant de la un serviciu web la altul!

Deoarece WSDL este XML, trebuie să scrieți despre asta direct în prima linie. Elementul rădăcină al fișierului ar trebui să fie întotdeauna numit „ definiții»:


De obicei, WSDL constă din 4-5 blocuri principale. Primul bloc este definiția unui serviciu web sau, cu alte cuvinte, punctul de intrare.


Aici scrie că avem un serviciu numit - „ Serviciu SMS" În principiu, toate denumirile din fișierul WSDL pot fi schimbate de dvs. în orice doriți, pentru că nu joacă absolut niciun rol.

După aceasta vă anunțăm că în serviciul nostru web " Serviciu SMS" există un punct de intrare ("port") numit " SMSServicePort" La acest punct de intrare vor fi trimise toate cererile de la clienți către server. Și indicați în elementul „ abordare» link către fișierul de gestionare care va accepta cereri.

Odată ce am definit serviciul web și am specificat punctul de intrare pentru acesta, trebuie să le legăm procedurile acceptate:


Pentru a face acest lucru, listează ce operațiuni și sub ce formă vor fi numite. Acestea. pentru port" SMSServicePort" o legare este definită sub numele " SMSServiceBinding", care are un tip de apel " rpc„și HTTP este folosit ca protocol de transmisie. Astfel, am indicat aici că vom efectua un apel RPC prin HTTP. După aceasta, descriem ce proceduri ( Operațiune) sunt acceptate în serviciul web. Vom sprijini o singură procedură – „ Trimite SMS" Prin această procedură minunatele noastre mesaje vor fi trimise către server! După ce procedura a fost declarată, este necesar să se indice sub ce formă vor fi transmise datele. În acest caz, este indicat că vor fi folosite plicuri SOAP standard.

După aceea, trebuie să legăm procedura de mesaje:


Pentru a face acest lucru, precizăm că legarea noastră este de tipul " SMSServicePortType"și în elementul" portType„cu denumirea de același tip, indicăm legarea procedurilor de mesaje. Și astfel, mesajul primit (de la client la server) va fi numit „ trimiteSmsRequest", și de ieșire (de la server la client) " trimiteSmsResponse" Ca toate numele din WSDL, numele mesajelor de intrare și de ieșire sunt arbitrare.

Acum trebuie să descriem mesajele în sine, de ex. de intrare și de ieșire:


Pentru a face acest lucru adăugăm elementele " mesaj"cu nume" trimiteSmsRequest" Și " trimiteSmsResponse„, respectiv. În ele indicăm că intrarea ar trebui să fie un plic a cărui structură corespunde tipului de date " Cerere" După care se returnează de la server un plic care conține tipul de date - „ Raspuns».

Acum trebuie să facem doar puțin - adăugați o descriere a acestor tipuri în fișierul nostru WSDL! Și cum credeți că WSDL descrie datele de intrare și de ieșire? Cred că ai înțeles deja totul cu mult timp în urmă și ți-ai spus că folosind scheme XML! Și vei avea perfectă dreptate!


Ne poți felicita! Primul nostru WSDL a fost scris! Și suntem cu un pas mai aproape de a ne atinge obiectivul.
În continuare, ne vom uita la ce ne oferă PHP pentru dezvoltarea propriilor aplicații distribuite.

5 Primul nostru server SOAP

Mai devreme am scris că pentru a crea un server SOAP în PHP vom folosi clasa încorporată SoapServer. Pentru ca toate acțiunile ulterioare să se întâmple în același mod ca și pentru mine, va trebui să vă modificați puțin PHP. Pentru a fi și mai precis, trebuie să vă asigurați că aveți instalată extensia „php-soap”. Cel mai bine este să citiți cum să îl instalați pe serverul dvs. web de pe site-ul oficial PHP (vezi lista de referințe).

După ce totul a fost instalat și configurat, va trebui să creăm un fișier în folderul rădăcină al găzduirii dvs. „ smsservice.php» cu următorul conținut:

setClass("SoapSmsGateWay"); //Porniți serverul $server->handle();
Sper că nu este nevoie să explic ce este deasupra liniei cu funcția „ini_set”. Deoarece acolo se determină ce anteturi HTTP vom trimite de la server către client și se configurează mediul. În conformitate cu „ini_set”, dezactivăm memorarea în cache a fișierului WSDL, astfel încât modificările noastre să aibă efect imediat asupra clientului.

Acum ajungem la server! După cum puteți vedea, întregul server SOAP are doar trei linii! Pe prima linie, creăm o nouă instanță a obiectului SoapServer și transmitem adresa descrierii noastre WSDL a serviciului web constructorului său. Acum știm că va fi localizat în rădăcina găzduirii într-un fișier cu numele auto-explicativ „ smsservice.wsdl.php" În a doua linie, îi spunem serverului SOAP care clasă trebuie extrasă pentru a procesa plicul primit de la client și a returna plicul cu răspunsul. După cum probabil ați ghicit, singura noastră metodă va fi descrisă în această clasă Trimite SMS. Pe a treia linie pornim serverul! Gata, serverul nostru este gata! Cu care ne felicit pe toti!

Acum trebuie să creăm fișierul WSDL. Pentru a face acest lucru, puteți fie să-i copiați pur și simplu conținutul din secțiunea anterioară, fie să vă luați libertăți și să-l „șablonați” puțin:

"; ?> /" 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" />
În această etapă, ar trebui să fim complet mulțumiți de serverul rezultat, deoarece Putem înregistra plicurile care vin la el și apoi analizăm cu calm datele primite. Pentru a primi ceva pe server, avem nevoie de un client. Deci, să trecem la asta!

6 client SOAP pe drum

În primul rând, trebuie să creăm un fișier în care vom scrie clientul. Ca de obicei, îl vom crea în rădăcina gazdei și îl vom numi " client.php", iar în interior vom scrie următoarele:

MessageList = new MessageList(); $req->messageList->message = mesaj nou(); $req->messageList->message->phone = "79871234567"; $req->messageList->message->text = "Testează mesajul 1"; $req->messageList->message->date = "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));
Să ne descriem obiectele. Când am scris WSDL, acesta a descris trei entități pentru plicul primit pe server: Cerere, Listă de mesajeȘi Mesaj. În consecință, clasele Cerere, Listă de mesajeȘi Mesaj sunt reflectări ale acestor entități în scriptul nostru PHP.

Odată ce am definit obiectele, trebuie să creăm un obiect ( $req), pe care îl vom trimite către server. După care vin cele mai prețuite două replici pentru noi! Clientul nostru SOAP! Credeți sau nu, acest lucru este suficient pentru ca serverul nostru să înceapă să primească mesaje de la client, precum și pentru ca serverul nostru să le primească și să le proceseze cu succes! În primul dintre ele, creăm o instanță a clasei SoapClient și transmitem adresa locației fișierului WSDL constructorului acestuia, iar în parametri indicăm în mod explicit că vom lucra folosind protocolul SOAP versiunea 1.2. Pe linia următoare numim metoda Trimite SMS obiect $clientși afișați imediat rezultatul în browser.
Hai să-l rulăm și să vedem ce avem în sfârșit!

Următorul obiect mi-a fost returnat de pe server:

Object(stdClass) public "status" => boolean adevărat
Și asta este grozav, pentru că... Acum știm sigur că serverul nostru funcționează și nu numai că funcționează, dar poate returna și câteva valori clientului!

Acum să ne uităm la jurnalul pe care îl păstrăm cu prudență pe partea serverului! În prima parte vedem datele brute care au ajuns pe server:

79871234567 Mesajul de testare 1 2013-07-21T15:00:00.26 15
Acesta este plicul. Acum știi cum arată! Dar este puțin probabil să fim interesați să ne uităm la el tot timpul, așa că haideți să deserializăm obiectul din fișierul jurnal și să vedem dacă totul este bine:

Object(stdClass) public "messageList" => object(stdClass) public "message" => object(stdClass) public "phone" => șir "79871234567" (lungime=11) public "text" => șir "Test mesaj 1 " (lungime=37) public "date" => șir "2013-07-21T15:00:00.26" (lungime=22) public "tip" => șir "15" (lungime=2)
După cum puteți vedea, obiectul a fost deserializat corect, pentru care vreau să ne felicit pe toți! Ceva mai interesant ne așteaptă în continuare! Și anume, vom trimite clientul către server nu doar un mesaj SMS, ci un pachet întreg (mai precis, trei)!

7 Trimiterea obiectelor complexe

Să ne gândim cum putem transfera o grămadă de mesaje pe server într-un singur pachet? Probabil cea mai simplă modalitate ar fi să organizați o matrice în interiorul elementului messageList! Să o facem:

// creăm un obiect de trimis la server $req = new Request(); $req->messageList = new MessageList(); $msg1 = mesaj nou(); $msg1->telefon = "79871234567"; $msg1->text = "Mesajul de testare 1"; $msg1->date = "2013-07-21T15:00:00.26"; $msg1->tip = 15; $msg2 = mesaj nou(); $msg2->telefon = "79871234567"; $msg2->text = "Test mesajul 2"; $msg2->date = "2014-08-22T16:01:10"; $msg2->tip = 16; $msg3 = mesaj nou(); $msg3->telefon = "79871234567"; $msg3->text = "Test mesajul 3"; $msg3->date = "2014-08-22T16:01:10"; $msg3->tip = 17; $req->messageList->message = $msg1; $req->messageList->message = $msg2; $req->messageList->message = $msg3;
Jurnalele noastre indică faptul că următorul pachet a fost primit de la client:

79871234567 Mesajul de testare 1 2013-07-21T15:00:00.26 15 79871234567 Mesajul de testare 2 22-08-2014T16:01:10 16 79871234567 Mesajul de testare 3 22-08-2014T16:01:10 17
Ce prostii, zici? Și vei avea dreptate într-un fel, pentru că... De îndată ce am aflat că un obiect a părăsit clientul, acesta a ajuns la serverul nostru în absolut aceeași formă sub forma unui plic. Adevărat, mesajele SMS nu erau serializate în XML în modul în care aveam nevoie - trebuiau să fie împachetate în elemente mesaj, nu în Struct. Acum să vedem în ce formă un astfel de obiect vine la metodă Trimite SMS:

Object(stdClass) public "messageList" => obiect(stdClass) public "message" => object(stdClass) public "Struct" => matrice (dimensiune=3) 0 => obiect(stdClass) public "telefon" => șir „79871234567” (lungime=11) public „text” => șir „Test mesajul 1” (lungime=37) public „date” => șir „2013-07-21T15:00:00.26” (lungime=22) public „ tip" => șir "15" (lungime=2) 1 => obiect(stdClass) public "telefon" => șir "79871234567" (lungime=11) public "text" => șir "Mesaj de testare 2" (lungime= 37) public „date” => șir „2014-08-22T16:01:10” (lungime=19) public „tip” => șir „16” (lungime=2) 2 => obiect(stdClass) public „telefon " => șir "79871234567" (lungime=11) public "text" => șir "Test mesaj 3" (lungime=37) public "date" => șir "2014-08-22T16:01:10" (lungime= 19) public „type” => șir „17” (lungime=2)
Ce ne oferă această cunoaștere? Doar că calea pe care am ales-o nu este corectă și nu am primit răspuns la întrebarea - „Cum putem obține structura corectă de date pe server?” Dar vă sugerez să nu disperați și să încercați să convertiți matricea noastră la tipul un obiect:

$req->messageList->message = (obiect)$req->messageList->mesaj;
În acest caz, vom primi un alt plic:

79871234567 Mesajul de testare 1 2013-07-21T15:00:00.26 15 79871234567 Mesajul de testare 2 22-08-2014T16:01:10 16 79871234567 Mesajul de testare 3 22-08-2014T16:01:10 17
A intrat în metodă Trimite SMS obiectul are următoarea structură:

Object(stdClass) public "messageList" => obiect(stdClass) public "message" => object(stdClass) public "BOGUS" => matrice (dimensiune=3) 0 => obiect(stdClass) public "telefon" => șir „79871234567” (lungime=11) public „text” => șir „Test mesajul 1” (lungime=37) public „date” => șir „2013-07-21T15:00:00.26” (lungime=22) public „ tip" => șir "15" (lungime=2) 1 => obiect(stdClass) public "telefon" => șir "79871234567" (lungime=11) public "text" => șir "Mesaj de testare 2" (lungime= 37) public „date” => șir „2014-08-22T16:01:10” (lungime=19) public „tip” => șir „16” (lungime=2) 2 => obiect(stdClass) public „telefon " => șir "79871234567" (lungime=11) public "text" => șir "Test mesaj 3" (lungime=37) public "date" => șir "2014-08-22T16:01:10" (lungime= 19) public „type” => șir „17” (lungime=2)
În ceea ce mă privește, „suma nu se schimbă din schimbarea locurilor termenilor” (c). Ce FALS, Ce Struct– încă nu ne-am atins scopul! Și pentru a realiza acest lucru, trebuie să ne asigurăm că în locul acestor nume de neînțeles este afișat cel nativ. mesaj. Dar autorul nu știe încă cum să realizeze acest lucru. Prin urmare, singurul lucru pe care îl putem face este să scăpăm de recipientul suplimentar. Cu alte cuvinte, acum ne vom asigura că în loc de mesaj a devenit FALS! Pentru a face acest lucru, schimbați obiectul după cum urmează:

// creăm un obiect de trimis la server $req = new Request(); $msg1 = mesaj nou(); $msg1->telefon = "79871234567"; $msg1->text = "Mesajul de testare 1"; $msg1->date = "2013-07-21T15:00:00.26"; $msg1->tip = 15; $msg2 = mesaj nou(); $msg2->telefon = "79871234567"; $msg2->text = "Test mesajul 2"; $msg2->date = "2014-08-22T16:01:10"; $msg2->tip = 16; $msg3 = mesaj nou(); $msg3->telefon = "79871234567"; $msg3->text = "Test mesajul 3"; $msg3->date = "2014-08-22T16:01:10"; $msg3->tip = 17; $req->messageList = $msg1; $req->messageList = $msg2; $req->messageList = $msg3; $req->messageList = (obiect)$req->messageList;
Ce se întâmplă dacă avem noroc și numele corect iese din diagramă? Pentru a face acest lucru, să ne uităm la plicul care a sosit:

79871234567 Mesajul de testare 1 2013-07-21T15:00:00.26 15 79871234567 Mesajul de testare 2 22-08-2014T16:01:10 16 79871234567 Mesajul de testare 3 22-08-2014T16:01:10 17
Da, nu s-a întâmplat un miracol! FALS– nu vom câștiga! A venit la Trimite SMS obiectul în acest caz va arăta astfel:

Object(stdClass) public "messageList" => object(stdClass) public "BOGUS" => array (size=3) 0 => object(stdClass) public "phone" => șir "79871234567" (lungime=11) public " text" => șir "Test mesajul 1" (lungime=37) public "date" => șir "2013-07-21T15:00:00.26" (lungime=22) public "type" => șir "15" (lungime =2) 1 => obiect(stdClass) public "telefon" => șir "79871234567" (lungime=11) public "text" => șir "Test mesaj 2" (lungime=37) public "date" => șir " 2014-08-22T16:01:10" (lungime=19) public "type" => șir "16" (lungime=2) 2 => obiect(stdClass) public "telefon" => șir "79871234567" (lungime= 11) public "text" => șir "Test mesajul 3" (lungime=37) public "date" => șir "2014-08-22T16:01:10" (lungime=19) public "type" => șir " 17" (lungime=2)
După cum se spune – „Aproape”! Pe această notă (puțin tristă), îmi propun să încheiem treptat lucrurile și să tragem niște concluzii pentru noi înșine.

8 Concluzie

In sfarsit am ajuns aici! Să ne dăm seama ce poți face acum:
  • puteți scrie fișierul WSDL necesar serviciului dvs. web;
  • puteți scrie cu ușurință propriul client care poate comunica cu serverul prin SOAP;
  • vă puteți scrie propriul server care comunică cu lumea exterioară prin SOAP;
  • puteți trimite matrice de același tip de obiecte către server de la clientul dvs. (cu unele restricții).
Am făcut și câteva descoperiri în timpul micii noastre cercetări:
  • clasa nativă SoapClient nu serializează corect structurile de date de același tip în XML;
  • atunci când serializează o matrice în XML, acesta creează un element suplimentar numit Struct;
  • atunci când serializează un obiect în XML, acesta creează un element suplimentar numit FALS;
  • FALS mai puțin rău decât Struct datorită faptului că plicul este mai compact (nu se adaugă spații de nume suplimentare în antetul XML al plicului);
  • Din păcate, clasa SoapServer nu validează automat datele plicului cu schema noastră XML (poate că nici alte servere nu fac acest lucru).

Protocol simplu de acces la obiect (SOAP) este un protocol bazat pe XML care definește regulile de transmitere a mesajelor prin Internet între diferite sisteme de aplicații. Este folosit în principal pentru apelurile de procedură de la distanță. SOAP a fost conceput inițial pentru a funcționa „peste” HTTP (pentru a simplifica integrarea SOAP în aplicațiile Web), dar acum pot fi utilizate și alte protocoale de transport, cum ar fi SMTP.

Să presupunem că creați un serviciu de acces la aplicații pe Internet; consumatorii interacționează cu acest serviciu furnizându-i informații. Serverele dumneavoastră procesează datele și returnează rezultate consumatorilor. Care este cel mai bun mod de a menține comunicarea cu sistemul?

Puteți crea o aplicație client-server personalizată și puteți solicita consumatorilor să folosească un program client personalizat pentru a vă accesa serviciul. Dar dacă sunteți serios să vă găsiți în afacerea pe internet, va trebui să creați un client care rulează pe toate platformele client posibile - Windows, Macintosh, Unix, Linux etc. Cu alte cuvinte, va trebui să scrieți mulți clienți diferiți .

Ce părere aveți despre utilizarea web-ului? Această soluție este, desigur, destul de acceptabilă, dar este strâns legată de implementarea browserului și, din nou, va trebui să creați infrastructura pentru a trimite și primi informații de intrare și de ieșire, precum și de a formata și de a împacheta datele pentru un astfel de schimb. Puteți alege Java sau ActiveX pentru a implementa aplicații complexe, dar apoi unii utilizatori vă vor refuza serviciile din cauza cerințelor de lățime de bandă clar umflate și a securității inadecvate.

Tot ceea ce este necesar este un protocol simplu care simplifică împachetarea datelor aplicației și transmiterea lor pe Web utilizând XML adaptat la conținut. Procedând astfel, se asigură că atât expeditorul, cât și destinatarul pot interpreta cu ușurință conținutul oricărui mesaj. În același timp, datorită utilizării protocolului HTTP Web ca transport, va fi posibilă eliminarea necesității reducerii nivelului de protecție firewall.

Protocolul SOAP (Simple Object Access Protocol) bine descris este un protocol simplu „lipici” care permite gazdelor să invoce de la distanță obiectele aplicației și să returneze rezultate. SOAP oferă un set minim de condiții pentru ca o aplicație să transmită mesaje: un client poate trimite un mesaj pentru a invoca un obiect de program, iar serverul poate returna rezultatele apelului respectiv.

SOAP este destul de simplu: mesajele sunt documente XML care conțin comenzi SOAP. Deși SOAP poate fi teoretic legat de orice protocol de transport pentru aplicații, este de obicei folosit împreună cu HTTP.

Kennard Scribner, unul dintre autorii cărții Înțelegerea SOAP: soluția autorizată(Macmillan USA, 2000), spune că SOAP funcționează prin conversia informațiilor necesare apelării unei metode (cum ar fi valorile argumentelor și identificatorii de tranzacție) în format XML.

Datele sunt încapsulate în HTTP sau alt protocol de transport și transmise destinatarului, care este de obicei serverul. Acest server extrage datele SOAP din pachet, efectuează procesarea necesară și returnează rezultatele ca răspuns SOAP.

Scribner a remarcat că SOAP acționează ca un protocol de apel de procedură la distanță, la fel ca protocolul de invocare a metodei de la distanță din Java sau Protocolul general Inter-ORB din CORBA.

Deoarece HTTP și XML sunt folosite practic peste tot, SOAP pare a fi cel mai scalabil protocol de apel de procedură de la distanță construit până în prezent, a spus Scribner. SOAP nu este proiectat să acționeze ca o arhitectură completă a obiectelor.

SOAP nu înlocuiește protocolul Remote Method Invocation în Java, Distributed Component Object Model și CORBA; oferă reguli pe care oricare dintre aceste modele le poate folosi. SAPUNUL nu este o soluție completă. Nu acceptă activarea sau protecția obiectelor. Potrivit Scribner, dezvoltatorii SOAP „încred că utilizatorii vor adăuga ei înșiși acest cod”, construindu-l pe deasupra SOAP, mai degrabă decât făcându-l parte a protocolului în sine.

Figura prezintă un exemplu preluat din specificația SOAP 1.1 în care o gazdă solicită un serviciu de cotație pentru prețul unui anumit stoc. Solicitarea SOAP este încorporată într-un HTTP POST, iar corpul solicitării specifică tipul cererii și parametrul - simbolul bursier. Răspunsul oferă, de asemenea, un obiect XML încapsulat în răspunsul HTTP cu o singură valoare returnată (34,5 în acest caz).

Caracteristicile SOAP

Cu SOAP, dezvoltatorii pot crea servicii Web la fel de repede cum pot scrie mesaje SOAP pentru a apela programe pentru aplicațiile existente și apoi pot adăuga acele aplicații în pagini web simple. Dar, în plus, dezvoltatorii au capacitatea de a utiliza apeluri SOAP în aplicații dedicate și de a crea aplicații care pot fi portate pe paginile Web ale altor persoane, evitând astfel procesul de dezvoltare consumatoare de timp și costisitoare.

Potrivit lui Mark Stiver, un alt autor al cărții Understanding SOAP, acesta este tocmai scopul pe care Microsoft îl urmărește cu platforma sa promițătoare .Net. „Aici este locul în care săpunul strălucește. Le oferă dezvoltatorilor o modalitate foarte bună de a crea aplicații fără a fi nevoiți să vă faceți griji cu privire la potențialele incompatibilități”, spune el.

Exemplu de SAPUN

Următorul exemplu ilustrează o solicitare SOAP numită GetLastTradePrice, care permite unui client să trimită o solicitare pentru cele mai recente cotații pentru un anumit stoc.

POST/StockQuote HTTP/1.1
Gazdă: stockquoteserver.com
Tipul de conținut: text/xml; charset="utf-8"
Durata conținutului: nnnn
SAPUNActiune:„Unele-URI”

Primele cinci linii (parte din antetul HTTP) specifică tipul mesajului (POST), gazda, tipul încărcăturii și lungimea sarcinii utile, iar antetul SOAPAction specifică scopul solicitării SOAP. Mesajul SOAP în sine este un document XML cu mai întâi un plic SOAP, apoi un element XML care specifică spațiul de nume și atributele SOAP, dacă există. Un plic SOAP poate include un antet (dar nu în acest caz) urmat de un corp SOAP. În exemplul nostru, corpul conține cererea GetLastTradePrice și simbolul stocului pentru care sunt solicitate cele mai recente cotații. Răspunsul la această interogare ar putea arăta astfel:

HTTP/1.1 200 OK
Tipul de conținut: text/xml; charset="utf-8"
Durata conținutului: nnnn

Din nou, primele trei linii fac parte din antetul HTTP; Mesajul SOAP în sine constă dintr-un plic care conține răspunsul la cererea inițială, etichetat GetLastTradePriceResponse, și include valoarea returnată, în cazul nostru 34.5.

În general, astăzi există protocoale standard de schimb de date XML:

  • XML-RPC– treci pachetul și indică ce metodă de pe server vrei să apelezi.
  • ODIHNĂ- există câteva obiecte pe server. Fiecare obiect este caracterizat de un fel de identificator. Fiecare element are propria sa adresă URL. Puteți face următoarele cu orice element: inserați, ștergeți, actualizați, selectați. Pur și simplu trimiteți cererea dorită către server (de exemplu, introduceți un astfel de element). Schimbul client-server se bazează fie pe JSON, fie pe XML.

SOAP (arhitectura orientată pe servicii, un set de servicii slab cuplate care interacționează între ele) se bazează pe RPC. Principalul avantaj al RPC este numărul mic de resurse de rețea (puncte de intrare) și numeroasele metode implicate. În ciuda acestui avantaj, RPC este un protocol învechit care are o serie de dezavantaje:

  • Valabilitatea unui mesaj XML-RPC nu poate fi verificată. Vechiul protocol a fost creat înainte ca schemele (metode de validare a datelor) să fie standardizate în XML. Acestea. Serverul acceptă cereri, trebuie să se asigure că solicitările sunt pentru el și că datele sunt consecvente. În XML-RPC, tipurile de date sunt declarate pentru aceasta, dar aceasta este o verificare a tipului de date, iar consistența datelor nu este verificată (că ați primit o structură cu toți parametrii necesari).
  • Nu puteți crea mesaje combinate.
  • Nu puteți folosi spațiul și timpul (a apărut după crearea RPC).
  • Nu puteți extinde mesajul, de exemplu. adăugați informații suplimentare.

Toate aceste neajunsuri au fost rezolvate în XML Schema. Acesta este standardul industrial pentru descrierea unui document XML. Acestea. este o modalitate de a modela date arbitrare. O schemă XML poate descrie un model (relațiile dintre elemente și atribute și structura acestora), tipuri de date (caracterizează tipuri de date) și un dicționar (nume de elemente și atribute).

Pe baza tuturor deficiențelor XML-RPC, a fost creat protocolul SOAP.

SĂPUN(Simle Object Access Protocol) - protocol de acces la un obiect (la punctul de intrare). Astăzi este principalul standard industrial pentru construirea de aplicații distribuite.

Reprezintă extensii ale limbajului XML-RPC. Acestea. este construit pe principiul: 1 punct de intrare și orice metode. Protocolul în sine în ceea ce privește transportul (cum se transferă date) oferă o gamă largă de opțiuni: SMTP, FTP, HTTP, MSMQ.

SOAP stă la baza implementării serviciilor web XML (servicii web XML). Dezavantajul SOAP este că este greu de învățat.

SOAP se bazează pe schimbul de mesaje între un client și un server (sincron și asincron). Fiecare mesaj conține informații despre date (ce date sunt transmise și primite). SOAP descrie în prealabil întreaga structură a unui mesaj folosind scheme XML: ce ar trebui să fie în mesaj, cum va fi transmis. Acest lucru face posibil, fără a cunoaște serverul, să înțelegem ce se întâmplă acolo și îi permite serverului să verifice dacă acest mesaj este potrivit.

Schema XML

Scopul unei scheme este de a descrie structura datelor, de ex. ce avem. Toate datele sunt împărțite în tipuri simple și complexe (scalare și structuri). Un tip simplu (șir, număr, boolean, dată) nu va conține niciodată nimic în interior. Și o structură (obiect) poate conține proprietăți.

Operații SOAP de bază

  • Nu doar un simplu schimb de informații client-server. Dar și recunoașterea automată a serverului și căutarea acestui server, adică. clientul poate nici măcar să nu știe nimic despre server. Acestea. clientul caută mai întâi serverul, găsește servicii potrivite, înțelege ce metode există, ce are serverul și îl numește.
  • Serverul își publică informațiile (locația, ce metode acceptă) astfel încât clientul să găsească acest server. Publicarea are loc în directorul UDDI.

Structura mesajului SOAP:

  • Plic SOAP - acesta include întregul mesaj. Constă dintr-un antet și un corp.
  • Antet SOAP (antet) - informații suplimentare (autorizare, de exemplu).
  • SOAP Corp (corp) - mesajul în sine.
  • SOAP Fault (eroare) este o metodă de transmitere a unei erori de la server către client.

WSDL

WSDL(Web Services Description Language) - limbaj pentru descrierea serviciilor web. Folosit în SOAP. Acesta este un fel de document care descrie totul: ce spații de nume au fost folosite, ce scheme de date au fost folosite, ce tipuri de mesaje așteaptă serverul de la client, ce plicuri aparțin cărei metode, ce metode există, la ce adresă să trimită etc. . De fapt, WSDL este un serviciu web. Este suficient ca clientul să studieze conținutul acestui document, el știe deja totul despre server.

Orice server trebuie să publice WSDL.

WSDL este format din blocuri:

  • Definiția serviciului în sine, de ex. punctul de intrare, portul este indicat.
  • Formatul metodelor. Punctul de intrare este legat de operațiuni, de exemplu. ce metode suporta? Sunt indicate tipul apelului și metoda de transmitere. În interiorul fiecărei metode există o explicație a formei în care sunt transmise datele – sub formă de SOAP.
  • Metode de legare la un mesaj.
  • Descrierea mesajelor în sine.

Titlul subiectului este într-adevăr o întrebare, pentru că... Eu însumi nu știu ce este și pentru prima dată voi încerca să lucrez cu el în cadrul acestui articol. Singurul lucru pe care îl pot garanta este că codul prezentat mai jos va funcționa, dar frazele mele vor fi doar presupuneri și presupuneri despre cum înțeleg eu însumi toate acestea. Deci să mergem...

Introducere

Trebuie să începem cu motivul pentru care a fost creat conceptul de servicii web. Până la apariția acestui concept în lume, deja existau tehnologii care permiteau aplicațiilor să interacționeze la distanță, unde un program putea apela la o metodă într-un alt program, care putea fi lansat pe un computer situat într-un alt oraș sau chiar țară. Toate acestea sunt prescurtate ca RPC (Remote Procedure Calling). Exemplele includ tehnologiile CORBA și pentru Java - RMI (Remote Method Invoking). Și totul pare să fie bine în ei, mai ales în CORBA, pentru că... Puteți lucra cu el în orice limbaj de programare, dar încă lipsea ceva. Cred că dezavantajul CORBA este că funcționează prin unele dintre propriile protocoale de rețea în loc de simplu HTTP, care se va potrivi prin orice firewall. Ideea serviciului web a fost de a crea un RPC care să fie inserat în pachetele HTTP. Astfel a început dezvoltarea standardului. Care sunt conceptele de bază ale acestui standard:
  1. SĂPUN. Înainte de a apela o procedură de la distanță, trebuie să descrii acest apel într-un fișier XML în format SOAP. SOAP este pur și simplu unul dintre numeroasele markupuri XML care sunt utilizate în serviciile web. Tot ceea ce dorim să trimitem undeva prin HTTP este mai întâi convertit într-o descriere XML SOAP, apoi introdus într-un pachet HTTP și trimis către un alt computer din rețea prin TCP/IP.
  2. WSDL. Există un serviciu web, adică un program ale cărui metode pot fi apelate de la distanță. Dar standardul cere ca acest program să fie însoțit de o descriere care spune că „da, ai dreptate - acesta este într-adevăr un serviciu web și poți apela astfel de metode din el”. Această descriere este reprezentată de un alt fișier XML, care are un alt format și anume WSDL. Acestea. WSDL este doar un fișier XML care descrie un serviciu web și nimic mai mult.
De ce întrebi atât de scurt? Nu poți fi mai precis? Probabil că este posibil, dar pentru a face acest lucru va trebui să apelați la cărți precum T. Mashnin, „Java Web Services”. Acolo, pe primele 200 de pagini, există o descriere detaliată a fiecărei etichete a standardelor SOAP și WSDL. Merită făcut? După părerea mea, nu, pentru că... toate acestea sunt create automat în Java și trebuie doar să scrieți conținutul metodelor care ar trebui să fie apelate de la distanță. Deci, un API precum JAX-RPC a apărut în Java. Dacă cineva nu știe, când spune că Java are așa și așa API, înseamnă că există un pachet cu un set de clase care încapsulează tehnologia în cauză. JAX-RPC a evoluat de-a lungul timpului de la o versiune la alta și în cele din urmă a devenit JAX-WS. WS înseamnă, în mod evident, WebService și ați putea crede că aceasta este pur și simplu o redenumire a RPC ca un cuvânt popular la modă în zilele noastre. Acest lucru nu este adevărat, pentru că Acum serviciile web s-au îndepărtat de ideea originală și vă permit nu numai să apelați metode de la distanță, ci și să trimiteți pur și simplu mesaje de document în format SOAP. Nu știu încă de ce este nevoie de acest lucru; este puțin probabil ca răspunsul aici să fie „doar în cazul în care este necesar”. Eu însumi aș dori să învăț de la camarazi mai experimentați. Și, în sfârșit, a apărut JAX-RS pentru așa-numitele servicii web RESTful, dar acesta este subiectul unui articol separat. Introducerea se poate încheia aici, pentru că... În continuare vom învăța să lucrăm cu JAX-WS.

Abordare generală

În serviciile web există întotdeauna un client și un server. Serverul este serviciul nostru web și uneori este numit punctul final (ca în, punctul final unde ajung mesajele SOAP de la client). Trebuie să facem următoarele:
  1. Descrieți interfața serviciului nostru web
  2. Implementați această interfață
  3. Lansați serviciul nostru web
  4. Scrieți un client și apelați de la distanță metoda de serviciu web dorită
Puteți lansa un serviciu web în diferite moduri: fie descrieți o clasă cu metoda principală și lansați serviciul web direct ca server, fie implementați-l pe un server precum Tomcat sau oricare altul. În cel de-al doilea caz, noi înșine nu lansăm un nou server și nu deschidem alt port pe computer, ci pur și simplu spunem containerului de servlet Tomcat că „am scris aici clase de servicii web, vă rugăm să le publicați astfel încât toți cei care vă contactează să poată folosiți utilizarea serviciului web.” Indiferent de metoda de lansare a serviciului web, vom avea acelasi client.

Server

Să lansăm IDEA și să creăm un nou proiect Creați un nou proiect. Să indicăm numele HelloWebServiceși apăsați butonul Următorul, apoi butonul finalizarea. În dosar src să creăm un pachet ru.javarush.ws. În acest pachet vom crea interfața HelloWebService: pachet ru. javarush. ws; // acestea sunt adnotări, i.e. o modalitate de a ne marca clasele și metodele, // în legătură cu tehnologia serviciilor web import javax. jws. WebMethod; import javax. jws. Serviciu web; import javax. jws. săpun. SAPUNLegare; // spunem că interfața noastră va funcționa ca un serviciu web@Serviciu web // spunem că serviciul web va fi folosit pentru a apela metode@SOAPBinding (style = SOAPBinding. Style. RPC) interfață publică HelloWebService ( // spunem că această metodă poate fi apelată de la distanță@WebMethod public String getHelloString(Nume șir) ; ) În acest cod, clasele WebService și WebMethod sunt așa-numitele adnotări și nu fac altceva decât să marcheze interfața noastră și metoda acesteia ca serviciu web. Același lucru este valabil și pentru clasa SOAPBinding. Singura diferență este că SOAPBinding este o adnotare cu parametri. În acest caz, parametrul de stil este utilizat cu o valoare care indică faptul că serviciul web va funcționa nu prin mesaje de document, ci ca un RPC clasic, de exemplu. a apela o metodă. Să implementăm logica interfeței noastre și să creăm o clasă HelloWebServiceImpl în pachetul nostru. Apropo, observ că terminarea unei clase cu Impl este o convenție în Java, conform căreia implementarea interfețelor este astfel desemnată (Impl - din cuvântul implementare, adică implementare). Aceasta nu este o cerință și sunteți liber să denumiți clasa cum doriți, dar bunele maniere o cer: pachet ru. javarush. ws; // aceeași adnotare ca atunci când descrieți interfața, import javax. jws. Serviciu web; // dar aici este folosit cu parametrul endpointInterface, // indicând numele complet al clasei de interfață a serviciului nostru web@WebService(endpointInterface= „ru.javarush.ws.HelloWebService”) clasa publică HelloWebServiceImpl implementează HelloWebService ( @Override public String getHelloString (nume șir) ( // returnează doar salutul returnează "Bună ziua, " + nume + "!" ; ) ) Să lansăm serviciul nostru web ca server independent, adică. fără participarea niciunui Tomcat și a serverelor de aplicații (acesta este un subiect pentru o discuție separată). Pentru a face acest lucru, în structura proiectului din folder src Să creăm un pachet ru.javarush.endpoint, iar în el vom crea o clasă HelloWebServicePublisher cu metoda principală: pachetul ru. javarush. punct final; // clasa pentru rularea unui server web cu servicii web import javax. xml. ws. Punct final; // clasa serviciului nostru web import ru. javarush. ws. HelloWebServiceImpl; clasă publică HelloWebServicePublisher ( public static void main (String... args) ( // porniți serverul web pe portul 1986 // și la adresa specificată în primul argument, // pornește serviciul web transmis în al doilea argument Punct final. publica ( „http://localhost:1986/wss/hello”, nou HelloWebServiceImpl () ); ) ) Acum să rulăm această clasă făcând clic Shift+F10. Nu va apărea nimic în consolă, dar serverul rulează. Puteți verifica acest lucru tastând linia http://localhost:1986/wss/hello?wsdl în browser. Pagina care se deschide, pe de o parte, demonstrează că avem un server web (http://) care rulează pe portul 1986 pe computerul nostru (localhost) și, pe de altă parte, arată o descriere WSDL a serviciului nostru web. Dacă opriți aplicația, descrierea va deveni indisponibilă, la fel ca și serviciul web în sine, așa că nu vom face acest lucru, ci vom trece la scrierea clientului.

Client

În folderul de proiect src Să creăm un pachet ru.javarush.client și în el clasa HelloWebServiceClient cu metoda principală: pachet ru. javarush. client; // necesar pentru a obține descrierea wsdl și prin ea // ajunge la serviciul web în sine import java. net. URL; // această excepție va apărea când lucrați cu un obiect URL import java. net. MalformedURLException; // clase pentru a analiza xml cu descrierea wsdl // și ajungeți la eticheta de serviciu din ea import javax. xml. spatiu de nume. QName; import javax. xml. ws. Serviciu; // interfața serviciului nostru web (avem nevoie de mai mult) import ru. javarush. ws. HelloWebService; clasă publică HelloWebServiceClient ( public static void main (String args) aruncă MalformedURLException ( // creează un link către descrierea wsdl URL URL = adresă URL nouă ( „http://localhost:1986/wss/hello?wsdl”) ; // Ne uităm la parametrii următorului constructor din prima etichetă a descrierii WSDL - definiții // uită-te la primul argument din atributul targetNamespace // uită-te la al 2-lea argument din atributul name QName qname = nou QName ("http://ws.site/" , "HelloWebServiceImplService" ); // Acum putem ajunge la eticheta de serviciu din descrierea wsdl, Service service = Service. create (url, qname); // și apoi până la eticheta de port imbricată în ea, astfel încât // obțineți un link către un obiect de serviciu web aflat la distanță de la noi HelloWebService hello = serviciu. getPort(HelloWebService.class); // Ura! Acum puteți apela metoda de la distanță Sistem. afară. println (bună ziua. getHelloString ("JavaRush")); ) ) Am dat maxim de comentarii la codul din listare. Nu am nimic de adăugat, așa că să alergăm (Shift+F10). Ar trebui să vedem textul în consolă: Bună ziua, JavaRush! Dacă nu l-ați văzut, atunci probabil ați uitat să porniți serviciul web.

Concluzie

Acest subiect a oferit o scurtă excursie în serviciile web. Încă o dată, voi spune că o mare parte din ceea ce am scris este presupunerea mea cu privire la modul în care funcționează și, prin urmare, nu ar trebui să aveți prea multă încredere în mine. Aș fi recunoscător dacă oamenii cunoscători mă corectează, pentru că atunci voi învăța ceva. UPD.

Ce este SAPUNUL?

SOAP înseamnă Simple Object Access Protocol. Sper că, după ce ai citit articolul, vei rămâne doar să te întrebi: „Care este acest nume ciudat?”

SOAP în forma sa actuală este o metodă de apel de procedură la distanță (RPC) printr-o rețea. (Da, este folosit și pentru a transfera documente ca XML, dar o vom omite pentru moment.)

Să ne dăm seama. Imaginați-vă că aveți un serviciu care returnează o cotație pentru un anumit ticker (simbol bursier). Trimite datele pe site-ul web Nasdaq și generează rezultatul dorit pe baza HTML-ului returnat. Apoi, pentru a permite altor dezvoltatori să-l folosească în aplicațiile lor, creați o componentă din acest serviciu care găsește informații despre cotații prin Internet. Funcționează excelent până când într-o zi Nasdaq își schimbă aspectul paginilor. Trebuie să reconsiderați întreaga logică a componentei și să trimiteți actualizări tuturor dezvoltatorilor care o folosesc. Și ei, la rândul lor, trebuie să trimită actualizări tuturor utilizatorilor lor. Dacă acest lucru se întâmplă mai mult sau mai puțin constant, vă puteți face o mulțime de dușmani printre colegii tăi dezvoltatori. Iar programatorii, după cum știți, nu trebuie băgați cu ei. Nu vrei să scoți mâine o fotografie cu pisica ta preferată din tocător de birou, nu-i așa?

Ce să fac? Să vedem... tot ce aveți nevoie este să furnizați o funcție care să ia ca intrare un simbol ticker (tip șir) și să returneze o cotație bursieră (tip float sau double). Deci nu ar fi mai ușor să lași dezvoltatorii tăi să apeleze cumva această funcție prin Internet? Grozav! Aceasta este și o noutate pentru mine, există COM și Corba și Java care fac asta de ani de zile... ceea ce este adevărat este adevărat, dar aceste metode nu sunt lipsite de defecte. Configurarea COM la distanță nu este banală. În plus, trebuie să deschideți atât de multe porturi în firewall încât nu puteți gestiona suficientă bere pentru un administrator de sistem. Da, și va trebui să uiți de utilizatorii tuturor sistemelor de operare, cu excepția Windows. Dar utilizatorii Linux sunt uneori interesați de schimb.

Deși se pare că nu totul este pierdut pentru utilizatorii Linux dacă folosesc DCOM, mai multe aici: http://www.idevresource.com/com/library/res/articles/comonlinux.asp.

Nu pot spune multe despre Corba și Java, așa că, ca exercițiu, invit cititorii să găsească dezavantajele acestor abordări.

SOAP este un standard care vă permite să descrieți un astfel de apel la distanță și forma în care va fi returnat rezultatul. Deci, trebuie să vă găzduiți funcția într-o aplicație accesibilă prin rețea și să primiți apeluri ca pachete SOAP. Apoi validați intrarea, rulați funcția și returnați rezultatul într-un nou pachet SOAP. Întregul proces poate rula prin HTTP, deci nu trebuie să deschideți o grămadă de porturi pe firewall. Este chiar simplu?

Despre ce este acest articol?

Acesta este primul dintr-o serie de articole pe care le scriem despre SOAP la Agni Software. În acest articol voi încerca să vă dau o idee despre ce este SOAP și cum să scrieți o aplicație care comunică cu un server SOAP.

Săpun și XML

Dacă SOAP încă vi se pare simplu, să adăugăm XML. Acum, în loc de numele funcției și parametrii, obținem un plic XML destul de complex, parcă conceput pentru a vă deruta. Dar nu te grăbi să te sperii. Există mai mult decât atât și trebuie să vedeți întreaga imagine pentru a aprecia complexitatea SOAP.
Dacă nu știți ce este XML, citiți mai întâi articolul meu despre XML aici: http://www.agnisoft.com/white_papers/xml_delphi.asp.

Toate pachetele SOAP sunt în format XML. Ce înseamnă? Să vedem. Aruncă o privire la această funcție (Pascal):
funcția GetStockQuote(Simbol: șir): dublu; Arată grozav, dar problema este că este Pascal. La ce folosește această definiție simplă pentru un dezvoltator Java? Sau pentru cineva care lucrează cu VB? Avem nevoie de ceva care să fie de înțeles pentru toată lumea, chiar și pentru programatorii VB. Deci, dați-le XML care conține aceleași informații (parametri, cotații bursiere etc.). Creați un pachet SOAP, care este în esență un apel la funcția dvs., împachetat în XML, astfel încât orice aplicație de pe orice platformă să îl poată înțelege. Acum să vedem cum arată apelul nostru SOAP:
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">


IBM


Informativ, nu? SAPUNUL devine din ce în ce mai ușor în fața ochilor noștri. Bine, glumele deoparte. Acum voi încerca să vă explic cum să înțelegeți acest apel SOAP.

Decodarea etichetelor

Prima etichetă care îți atrage atenția este . Această etichetă este învelișul exterior al unui pachet SOAP, care conține mai multe declarații de spațiu de nume care nu ne interesează în mod deosebit, dar sunt foarte importante pentru orice limbaj de programare sau parser. Spațiile de nume sunt definite pentru a se asigura că prefixele ulterioare precum „SOAP-ENV:” sau „xsd:” sunt înțelese de parser.

Următoarea etichetă – . (Am ratat o etichetă care nu este afișată aici - . Nu este în acest exemplu special, dar dacă doriți să citiți mai multe despre el, consultați specificația SOAP aici: http://www.w3.org/TR/SOAP/). Etichetă conține de fapt un apel SOAP.

Următoarea etichetă din listă este . Numele etichetei, GetStockQuote, este funcția apelată. În terminologia SOAP, aceasta se numește operație. Deci, GetStockQuote este operația care trebuie efectuată. ns1 este spațiul de nume care indică urn:xmethods-quotes în cazul nostru.

O notă despre spațiile de nume: un spațiu de nume face posibilă calificarea unei etichete XML. Nu puteți, de exemplu, să aveți două variabile cu același nume într-o procedură, dar dacă sunt în două proceduri diferite, nu este nicio problemă. Astfel, o procedură este un spațiu de nume, deoarece toate numele din ea sunt unice. În mod similar, etichetele XML își au domeniul de aplicare în spațiile de nume, așa că, având în vedere un spațiu de nume și un nume de etichetă, îl puteți identifica în mod unic. Vom defini spațiul de nume ca un URI pentru a diferenția NS1-ul nostru de copycats. În exemplul de mai sus, NS1 este un alias care indică urn:xmethods-quotes.

De asemenea, acordați atenție atributului encodingStyle - acest atribut determină modul în care este serializat apelul SOAP.

În interiorul unei etichete conţine parametri. În cel mai simplu caz al nostru, avem un singur parametru - tag . Observați această linie de lângă etichetă:
xsi:type="xsd:string"
Cam așa sunt definite tipurile în XML. (Observați cât de inteligent am folosit cuvântul „aproximativ” când am făcut o generalizare despre tehnologie care se poate schimba odată cu publicarea articolului.) Ce înseamnă exact acest lucru: un tip definit în spațiul de nume xsi, despre care veți observa că este definit în etichetă – xsd:string. Și acesta, la rândul său, este șir, definit în spațiul de nume xsd, din nou, definit mai devreme. (Sunt sigur că avocații ar fi pur și simplu încântați de toate acestea).

În interiorul unei etichete „IBM” este indicat. Aceasta este valoarea parametrului simbol al funcției GetStockQuote.

Ei bine, până la urmă, ca niște oameni cumsecade, am închis toate etichetele.

Așa că ne-am dat seama de pachetul SOAP care definește apelul către serverul SOAP. Iar serverul SOAP, folosind parsere XML, butonul roșu și stația spațială MIR, decodifică acest apel și determină că aveți nevoie de o cotație. El găsește imediat citatul potrivit și ți-l returnează sub acest formular:
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>


34.5


După ce am desfăcut plicul cu SOAP, am rupt panglicile și am foșnit ambalajul, aflăm că prețul acțiunilor IBM este de 34,5.

Majoritatea serverelor comerciale ar returna mult mai multe informații, cum ar fi în ce monedă și la ce preț a fost achiziționat ultimul stoc. Și prețul acțiunilor, poate, ar fi fost mai precis.

În acest fel, știm ce se așteaptă serverul SOAP și ce va returna. Deci CUM trimiteți aceste informații? Puteți folosi orice mijloc de transport. Cel mai acoperit este HTTP. Nu voi intra în detalii despre HTTP, pentru cei care nu știu, este ceea ce folosește browserul tău pentru a comunica cu site-urile pe care le vizitezi.

Solicitarea HTTP necesară va arăta cam așa:
POST /StockQuote HTTP/1.1
Gazdă: www.stockquoteserver.com

Lungimea conținutului: nnnn
Acțiune SOAP: „Unele-URI”

Pachetul de cerere de săpun aici... Singurul lucru care merită remarcat este antetul SOAPAction. Acest antet indică scopul solicitării și este obligatoriu. Fiecare server SOAP poate avea un număr nelimitat de funcții și poate folosi antetul SOAPAction pentru a determina ce funcție este apelată. Firewall-urile și multiplexerele pot filtra conținutul pe baza acestui antet.

Răspunsul SOAP de la serverul HTTP va arăta astfel:
HTTP/1.1 200 OK
Tip de conținut: text/xml; charset="utf-8"
Lungimea conținutului: nnnn

Pachetul Soap Response aici... De ce HTTP? În primul rând, administratorii de rețea nu vor trebui să deschidă o mulțime de porturi separate pentru apelurile SOAP... serverul web poate gestiona apelurile cu ușurință, deoarece Portul 80 este de obicei deschis tuturor pentru a primi cererile primite. Un alt avantaj este extensibilitatea serverelor web folosind CGI, ISAPI și alte module native. Această extensibilitate vă permite să scrieți un modul care procesează cererile SOAP fără a afecta alt conținut web.

Asta e tot

Sper că acest articol a ajutat să arunce o lumină asupra SOAP. Dacă sunteți încă aici și doriți să citiți mai multe despre acest subiect, vizitați site-ul web al autorilor: http://www.agnisoft.com/soap

  • Serghei Savenkov

    un fel de recenzie „scurtă”... de parcă s-ar grăbi undeva