Organisering av webtjenester


hatter 23. juli 2013 kl. 13:09

Skrive en SOAP klient-server-applikasjon i PHP

  • PHP
  • opplæringen

Hei alle sammen!
Det har seg slik at jeg nylig har engasjert meg i utviklingen av webtjenester. Men i dag handler ikke temaet om meg, men om hvordan vi kan skrive vår egen XML Web Service basert på SOAP 1.2-protokollen.

Jeg håper at etter å ha lest emnet, vil du kunne:

  • skrive din egen serverimplementering av en webapplikasjon;
  • skrive din egen klientimplementering av en webapplikasjon;
  • skrive din egen webtjenestebeskrivelse (WSDL);
  • sende arrays av samme type data til serveren av klienten.
Som du kanskje gjetter, vil all magien gjøres ved hjelp av PHP og de innebygde SoapClient- og SoapServer-klassene. Som kanin vil vi ha en tjeneste for å sende sms-meldinger.

1 Problemstilling

1.1 Grenser

I begynnelsen foreslår jeg å ta for oss resultatet som vi vil oppnå på slutten av temaet. Som det ble annonsert ovenfor, vil vi skrive en tjeneste for å sende sms-meldinger, og mer presist vil vi motta meldinger fra forskjellige kilder ved å bruke SOAP-protokollen. Etter det vil vi vurdere i hvilken form de kommer til serveren. Prosessen med å sette meldinger i kø for videre sending til leverandøren, er dessverre utenfor rammen av dette innlegget av mange grunner.

1.2 Hvilke data vil bli endret?

Ok, vi har grensene! Det neste trinnet som må gjøres er å bestemme hvilke data vi skal utveksle mellom serveren og klienten. Om dette emnet foreslår jeg å ikke være klokere på lenge og umiddelbart svare på hovedspørsmålene for deg selv:
  • Hvilke minimumsdata må sendes til serveren for å sende en SMS-melding til en abonnent?
  • Hva er minimumsmengden data som må sendes fra serveren for å tilfredsstille behovene til klienten?
Noe sier meg at for dette er det nødvendig å sende følgende:
  • mobiltelefonnummer, og
  • SMS-tekst.
I prinsippet er disse to karakteristikkene nok å sende, men det virker umiddelbart for meg som om det kommer en sms med bursdagshilsen til deg klokken 3 om morgenen, eller 4! I dette øyeblikket vil jeg være veldig takknemlig for alle som ikke har glemt meg! Derfor vil vi også sende til serveren og
  • datoen SMS-meldingen ble sendt.
Det neste jeg vil sende til serveren er
  • Meldingstype.
Denne parameteren er ikke obligatorisk, men den kan være veldig nyttig for oss hvis vi raskt trenger å fortelle sjefen hvor mange av kundene våre vi har "fornøyd" med nyhetene våre, og også trekke noen vakre statistikker om denne saken.

Og likevel har jeg glemt noe! Hvis vi reflekterer litt mer, er det verdt å merke seg at klienten kan sende én SMS-melding til serveren om gangen, eller et visst antall av dem. Med andre ord, i en datapakke kan det være fra én til uendelig av meldinger.

Som et resultat får vi at for å sende en SMS-melding, trenger vi følgende data:

  • mobilnummer,
  • sms tekst,
  • tidspunktet for å sende en SMS-melding til en abonnent,
  • meldingstype.

Vi svarte på det første spørsmålet, nå er det nødvendig å svare på det andre spørsmålet. Og kanskje jeg tillater meg å jukse litt. Derfor vil vi fra serveren bare sende boolske data, hvis verdi har følgende betydning:

  • TRUE - pakken har nådd serveren, bestått autentisering og satt i kø for sending til sms-leverandøren
  • FALSE - i alle andre tilfeller

Dette avslutter beskrivelsen av problemstillingen! Og til slutt, la oss komme ned til den mest interessante delen - vi vil finne ut hva slags merkelig beist denne SOAP er!

2 Hva er SOAP?

Generelt planla jeg i utgangspunktet ikke å skrive noe om hva SOAP er og ønsket å begrense meg til lenker til w3.org-siden med nødvendige spesifikasjoner, samt lenker til Wikipedia. Men helt til slutt bestemte jeg meg for å skrive en kort referanse om denne protokollen.

Og jeg starter min historie med det faktum at denne datautvekslingsprotokollen tilhører en undergruppe av protokoller basert på det såkalte RPC (Remote Procedure Call) paradigmet, hvis antipode er REST (Representational State Transfer, representative state transfer) . Du kan lese mer om dette i Wikipedia, lenker til artikler står helt på slutten av emnet. Fra disse artiklene må vi forstå følgende: "RPC-tilnærmingen lar deg bruke en liten mengde nettverksressurser med et stort antall metoder og en kompleks protokoll. Med en REST-tilnærming er antallet metoder og kompleksiteten til protokollen sterkt begrenset, noe som kan føre til et stort antall individuelle ressurser." Det vil si at i forhold til oss betyr dette at ved RPC-tilnærmingen vil siden alltid ha én inngang (lenke) til tjenesten og hvilken prosedyre som skal ringes for å behandle innkommende data vi sender sammen med dataene, mens med REST-tilnærmingen på vår Siden har mange innganger (lenker), som hver aksepterer og behandler kun visse data. Hvis noen som leser vet hvordan de skal forklare forskjellen i disse tilnærmingene enda enklere, så husk å skrive i kommentarene!

Det neste vi trenger å vite om SOAP er at denne protokollen bruker samme XML som en transport, noe som på den ene siden er veldig bra, fordi. vårt arsenal inkluderer umiddelbart den fulle kraften til stabelen med teknologier basert på dette markup-språket, nemlig XML-Schema - et språk for å beskrive strukturen til et XML-dokument (takk til Wikipedia!), som tillater automatisk validering av data som kommer til serveren fra klienter.

Og så, nå vet vi at SOAP er protokollen som brukes til å implementere ekstern prosedyrekall, og den bruker XML som en transport! Hvis du leser artikkelen på Wikipedia, så kan du derfra også lære at den kan brukes over alle applikasjonslagsprotokoller, og ikke bare sammenkobles med HTTP (dessverre vil vi i dette emnet kun vurdere SOAP over HTTP). Og vet du hva jeg liker best med alt dette? Hvis det ikke er noen gjetninger, så skal jeg gi deg et hint - SOAP!... Det er ingen gjetninger uansett?... Har du definitivt lest artikkelen på Wikipedia?... Generelt sett vil jeg ikke torturere deg videre. Derfor vil jeg umiddelbart gå videre til svaret: «SOAP (fra engelsk. Simple Object Access Protocol - en enkel protokoll tilgang til gjenstander; opp til spesifikasjon 1.2)". Høydepunktet på denne linjen er i kursiv! Jeg vet ikke hvilke konklusjoner du trakk fra alt dette, men jeg ser følgende - siden denne protokollen på ingen måte kan kalles "enkel" (og tilsynelatende til og med w3 er enig i dette), har den siden versjon 1.2 sluttet å være dekryptert i det hele tatt! Og det ble kjent som SOAP, bare SOAP og punktum.

Vel, ok, jeg ber om unnskyldning, skled litt til siden. Som jeg skrev tidligere, brukes XML som transport, og pakkene som kjører mellom klienten og serveren kalles SOAP-konvolutter. Hvis vi vurderer den generaliserte strukturen til konvolutten, vil den virke veldig kjent for deg, fordi ligner strukturen til en HTML-side. Den har en hoveddel - Konvolutt, som inkluderer seksjoner Overskrift og Kropp, eller Feil. PÅ Kropp data overføres og det er en obligatorisk del av konvolutten, mens Overskrift er valgfritt. PÅ Overskrift autorisasjon kan overføres, eller andre data som ikke er direkte relatert til inndataene til nettjenesteprosedyrene. Pro Feil det er ikke noe spesielt å fortelle, bortsett fra at det kommer til klienten fra serveren i tilfelle feil.

Det er her min oversiktshistorie om SOAP-protokollen slutter (vi vil se på selve konvoluttene og strukturen deres mer detaljert når klienten og serveren vår endelig lærer å kjøre dem inn i hverandre) og en ny begynner - om en SOAP-kompanjong kalt WSDL(Web Services Description Language). Ja, ja, dette er nettopp det som skremmer de fleste av oss fra selve forsøket på å ta og implementere vår egen API på denne protokollen. Som et resultat finner vi vanligvis opp hjulet vårt på nytt med JSON som transportmiddel. Så, hva er WSDL? WSDL er et språk for å beskrive nettjenester og få tilgang til dem, basert på XML (c) Wikipedia-språket. Hvis fra denne definisjonen hele den hellige betydningen av denne teknologien ikke blir tydelig for deg, vil jeg prøve å beskrive den med mine egne ord!

WSDL er designet for å tillate våre klienter å kommunisere normalt med serveren. For å gjøre dette er følgende informasjon beskrevet i filen med filtypen "*.wsdl":

  • Hvilke navneområder ble brukt,
  • Hvilke dataskjemaer ble brukt,
  • Hvilke typer meldinger forventer netttjenesten fra klienter,
  • Hvilke data tilhører hvilke nettjenesteprosedyrer,
  • Hvilke prosedyrer inneholder nettjenesten,
  • Hvordan skal klienten ringe netttjenesteprosedyrene,
  • Til hvilken adresse skal klientanrop sendes.
Som du kan se, er denne filen hele webtjenesten. Ved å spesifisere adressen til WSDL-filen i klienten, vil vi vite alt om enhver webtjeneste! Som et resultat trenger vi ikke å vite absolutt noe om hvor selve nettjenesten befinner seg. Det er nok å vite plasseringen til WSDL-filen! Snart vil vi finne ut at SOAP ikke er så skummelt som det er malt (c) russisk ordtak.

3 Introduksjon til XML-skjema

Nå vet vi mye om hva SOAP er, hva som er inne i den, og vi har en oversikt over hva slags teknologistabel som omgir den. Siden SOAP først og fremst er en metode for interaksjon mellom en klient og en server, og XML-markeringsspråket brukes som transport for det, vil vi i denne delen forstå litt hvordan automatisk datavalidering skjer gjennom XML-skjemaer.

Hovedoppgaven til skjemaet er å beskrive strukturen til dataene vi skal behandle. Alle data i XML-skjemaer er delt inn i enkel(skalær) og kompleks(strukturer) typer. Enkle typer inkluderer slike typer som:

  • linje,
  • Antall,
  • boolsk,
  • dato.
Noe veldig enkelt som ikke har noen utvidelser inni. Deres antipode er komplekse komplekse typer. Det enkleste eksemplet på en kompleks type som kommer til alle, er objekter. For eksempel en bok. Boken består av egenskaper: forfatter, tittel, pris, ISBN-nummer etc. Og disse egenskapene kan på sin side være både enkle typer og komplekse. Og XML-skjemaets oppgave er å beskrive det.

Jeg foreslår å ikke gå langt og skrive et XML-skjema for sms-meldingen vår! Nedenfor er xml-beskrivelsen av sms-meldingen:

71239876543 Testmelding 2013-07-20T12:00:00 12
Vårt komplekse typeskjema vil se slik ut:


Denne oppføringen lyder som følger: vi har en variabel " beskjed» skriv « beskjed" og det er en kompleks type kalt " beskjed", som består av et sekvensielt sett med elementer" telefon» type streng, « tekst» type streng, « Dato» type dato tid, « type» type desimal. Disse typene er enkle og er allerede definert i skjemadefinisjonen. Gratulerer! Vi har nettopp skrevet vårt første XML-skjema!

Jeg tror at betydningen av elementene " element"og" kompleksType» Alt ble mer eller mindre klart for deg, så vi vil ikke fokusere på dem lenger og bytte umiddelbart til komponistelementet « sekvens". Når vi bruker kompositorelementet " sekvens» vi informerer deg om at elementene som er inkludert i den alltid må være i den rekkefølgen som er spesifisert i ordningen, og at alle er obligatoriske. Men fortvil ikke! Det er ytterligere to komponistelementer i XML-skjemaer: valg"og" alle". Komponist valg" indikerer at det skal være ett av elementene oppført i den, og komponisten " alle» – enhver kombinasjon av de oppførte elementene.

Som du husker, i den første delen av emnet, ble vi enige om at pakken kan overføres fra en til uendelig av sms-meldinger. Derfor foreslår jeg å forstå hvordan slike data er deklarert i XML-skjemaet. Den generelle pakkestrukturen kan se slik ut:

71239876543 Testmelding 1 2013-07-20T12:00:00 12 71239876543 Testmelding N 2013-07-20T12:00:00 12
Skjemaet for en så kompleks type vil se slik ut:


Den første blokken inneholder den kjente erklæringen av den komplekse typen " beskjed". Hvis du legger merke til, så i hver enkel type inkludert i " beskjed", nye kvalifiserende attributter er lagt til " minForekommer"og" maxForekommer". Siden det ikke er vanskelig å gjette ut fra navnet, er den første ( minForekommer) indikerer at den gitte sekvensen må inneholde minst ett element av typen " telefon», « tekst», « Dato"og" type", mens den neste ( maxForekommer) attribute erklærer for oss at det er høyst ett slikt element i sekvensen vår. Som et resultat, når vi skriver skjemaene våre for data, får vi det bredeste valget når det gjelder hvordan de skal konfigureres!

Den andre blokken i skjemaet erklærer elementet " meldingsliste» skriv « Meldingsliste". Det er klart at " Meldingsliste' er en kompleks type som inneholder minst ett element ' beskjed”, men det maksimale antallet slike elementer er ikke begrenset!

4 Skrive WSDL

Husker du at WSDL er vår nettjeneste? Håper du husker! Mens vi skriver det, vil vår lille nettjeneste flyte på den. Så jeg foreslår at du ikke jukser.

Generelt, for at alt skal fungere riktig for oss, må vi overføre en WSDL-fil med riktig MIME-type til klienten. For å gjøre dette, må du konfigurere webserveren din tilsvarende, nemlig angi MIME-typen for filer med *.wsdl-utvidelsen til følgende linje:

Application/wsdl+xml
Men i praksis sendte jeg vanligvis HTTP-headeren via PHP " tekst/xml»:

Header("Content-Type: text/xml; charset=utf-8");
og alt fungerte utmerket!

Jeg vil advare deg med en gang, vår enkle nettjeneste vil ha en ganske imponerende beskrivelse, så ikke bli skremt, fordi. mesteparten av teksten er obligatorisk vann, og når den først er skrevet kan den hele tiden kopieres fra en nettjeneste til en annen!

Siden WSDL er XML, må du skrive om det direkte i den aller første linjen. Rotelementet til en fil må alltid hete " definisjoner»:


Vanligvis består WSDL av 4-5 hovedblokker. Den aller første blokken er definisjonen av en webtjeneste, eller med andre ord et inngangspunkt.


Det står her at vi har en tjeneste som heter - " SmsService". I prinsippet kan alle navn i WSDL-filen endres av deg til hva du måtte ønske, pga de spiller absolutt ingen rolle.

Etter det erklærer vi at i vår nettjeneste " SmsService" det er et inngangspunkt ("port"), som kalles " SmsServicePort". Det er til dette inngangspunktet at alle forespørsler fra klienter til serveren vil bli sendt. Og vi spesifiserer i elementet " adresse» en lenke til en behandlerfil som godtar forespørsler.

Etter at vi har definert en nettjeneste og angitt et inngangspunkt for den, må vi binde støttede prosedyrer til den:


For å gjøre dette, viser den hvilke operasjoner og i hvilken form y vil bli kalt. De. for havnen SmsServicePort» en binding ved navn « SmsServiceBinding", som har anropstypen " rpc” og HTTP brukes som overføringsprotokoll (transport). Derfor har vi her indikert at vi vil foreta et RPC-kall over HTTP. Etter det beskriver vi hvilke prosedyrer ( operasjon) støttes i nettjenesten. Vi støtter bare én prosedyre - " Send tekstmelding". Gjennom denne prosedyren vil våre fantastiske meldinger bli sendt til serveren! Etter at prosedyren er erklært, er det nødvendig å indikere i hvilken form dataene vil bli overført. I dette tilfellet er det spesifisert at standard SOAP-konvolutter skal brukes.

Etter det må vi binde prosedyren til meldingene:


For å gjøre dette spesifiserer vi at vår binding ("binding") er av typen " SmsServicePortType"og i elementet" portType» med samme typenavn, spesifiser bindingen av prosedyrer til meldinger. Og så vil den innkommende meldingen (fra klienten til serveren) bli kalt " sendSmsRequest", og utgående (fra serveren til klienten)" sendSmsResponse". Som alle navn i WSDL, er navnene på innkommende og utgående meldinger vilkårlige.

Nå må vi beskrive selve meldingene, dvs. innkommende og utgående:


For å gjøre dette legger vi til elementene " beskjed» med navn « sendSmsRequest"og" sendSmsResponse"henholdsvis. I dem indikerer vi at en konvolutt skal komme til inngangen, hvis struktur tilsvarer datatypen " Be om". Etter det returneres en konvolutt som inneholder datatypen fra serveren - " Respons».

Nå må vi bare gjøre litt - legg til en beskrivelse av disse typene til WSDL-filen vår! Og hvordan tror du WSDL beskriver innkommende og utgående data? Jeg tror at du har forstått alt lenge og sagt til deg selv det ved hjelp av XML-skjemaer! Og du vil ha helt rett!


Du kan gratulere oss! Vår første WSDL er skrevet! Og vi er et skritt nærmere å nå målet vårt.
Deretter vil vi ta for oss hva PHP gir oss for å utvikle våre egne distribuerte applikasjoner.

5 Vår første SOAP-server

Tidligere skrev jeg at for å lage en SOAP-server i PHP, vil vi bruke den innebygde SoapServer-klassen. For at alle videre handlinger skal skje på samme måte som mine, må du justere PHP-en din litt. For å være enda mer presis må du sørge for at du har installert utvidelsen "php-soap". Hvordan du legger den på webserveren din leses best på det offisielle PHP-nettstedet (se referanser).

Etter at alt er installert og konfigurert, må vi opprette filen " smsservice.php» med følgende innhold:

setClass("SoapSmsGateWay"); //Start serveren $server->handle();
Hva som er over linjen med "ini_set"-funksjonen, håper jeg, trenger ikke å forklares. Fordi den definerer hvilke HTTP-hoder vi skal sende fra serveren til klienten og konfigurerer miljøet. I "ini_set"-linjen deaktiverer vi caching av WSDL-filen slik at endringene våre i den umiddelbart trer i kraft på klienten.

Nå kommer vi til serveren! Som du kan se, er hele SOAP-serveren bare tre linjer lang! I den første linjen oppretter vi en ny forekomst av SoapServer-objektet og sender adressen til vår WSDL-webtjenestebeskrivelse til konstruktøren. Nå vet vi at den vil ligge i hostingroten i en fil med et talende navn " smsservice.wsdl.php". I den andre linjen forteller vi SOAP-serveren hvilken klasse den skal trekke for å behandle konvolutten mottatt fra klienten og returnere konvolutten med svaret. Som du kanskje har gjettet, er det i denne klassen vår eneste metode vil bli beskrevet. Send tekstmelding. I tredje linje starter vi serveren! Alt, serveren vår er klar! Som jeg gratulerer oss alle med!

Nå må vi lage en WSDL-fil. For å gjøre dette kan du enten kopiere innholdet fra forrige seksjon, eller ta deg friheter og "mal" det litt:

"; ?> /" 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" />
På dette stadiet bør den resulterende serveren passe oss helt, fordi. vi kan logge konvoluttene som kommer til den og deretter rolig analysere de innkommende dataene. For at vi skal motta noe på serveren trenger vi en klient. Så la oss fortsette med dem!

6 SOAP-klient på vei

Først av alt må vi lage en fil der vi skal skrive klienten. Som vanlig vil vi lage den ved roten til verten og kalle den " klient.php”, og inne skriver vi følgende:

meldingsliste = ny meldingsliste(); $req->messageList->message = ny melding(); $req->messageList->message->phone = "79871234567"; $req->messageList->message->text = "Testmelding 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));
La oss beskrive objektene våre. Da vi skrev WSDL, ble tre enheter beskrevet i den for konvolutten som kom inn på serveren: Be om, Meldingsliste og beskjed. Følgelig klassene Be om, Meldingsliste og beskjed er refleksjoner av disse enhetene i vårt PHP-skript.

Etter at vi har definert objektene, må vi lage et objekt ( $req), som vil bli sendt til serveren. Så kommer de to mest kjære linjene for oss! Vår SOAP-klient! Tro det eller ei, men dette er nok til at serveren vår begynner å sende meldinger fra klienten, så vel som at serveren vår skal kunne motta og behandle dem! I den første av dem oppretter vi en forekomst av SoapClient-klassen og sender adressen til plasseringen av WSDL-filen til konstruktøren, og angir eksplisitt i parametrene at vi vil jobbe med SOAP-protokollen versjon 1.2. På neste linje kaller vi metoden Send tekstmelding gjenstand $klient og umiddelbart vise resultatet i nettleseren.
La oss kjøre det og se hva vi endelig har fått!

Jeg mottok følgende objekt fra serveren:

Object(stdClass) public "status" => boolsk sann
Og dette er fantastisk, fordi. nå vet vi med sikkerhet at serveren vår fungerer og ikke bare fungerer, men også kan returnere noen verdier til klienten!

La oss nå se på loggen som vi holder på serversiden! I den første delen av den ser vi rådataene som kom inn på serveren:

79871234567 Testmelding 1 2013-07-21T15:00:00.26 15
Dette er konvolutten. Nå vet du hvordan det ser ut! Men vi er neppe interessert i å beundre det hele tiden, så la oss deserialisere objektet fra loggfilen og se om alt er bra med oss:

Object(stdClass) public "messageList" => objekt(stdClass) public "message" => objekt(stdClass) public "phone" => streng "79871234567" (lengde=11) offentlig "tekst" => streng "Testmelding 1 " (lengde=37) offentlig "date" => streng "2013-07-21T15:00:00.26" (lengde=22) offentlig "type" => streng "15" (lengde=2)
Som du kan se, ble objektet deserialisert riktig, noe jeg vil gratulere oss alle med! Neste, noe mer interessant venter oss! Vi vil nemlig sende av klienten til serveren ikke én sms-melding, men en hel pakke (for å være mer presis, tre hele)!

7 Sende komplekse objekter

La oss tenke på hvordan vi kan sende en hel haug med meldinger til serveren i én pakke? Sannsynligvis den enkleste måten ville være å organisere en matrise inne i messageList-elementet! La oss gjøre det:

// opprett et objekt som skal sendes til serveren $req = new Request(); $req->messageList = ny meldingsliste(); $msg1 = ny melding(); $msg1->phone = "79871234567"; $msg1->text = "Testmelding 1"; $msg1->date = "2013-07-21T15:00:00.26"; $msg1->type = 15; $msg2 = ny melding(); $msg2->phone = "79871234567"; $msg2->text = "Testmelding 2"; $msg2->date = "2014-08-22T16:01:10"; $msg2->type = 16; $msg3 = ny melding(); $msg3->phone = "79871234567"; $msg3->text = "Testmelding 3"; $msg3->date = "2014-08-22T16:01:10"; $msg3->type = 17; $req->messageList->message = $msg1; $req->messageList->message = $msg2; $req->messageList->message = $msg3;
Loggene våre viser at følgende pakke kom fra klienten:

79871234567 Testmelding 1 2013-07-21T15:00:00.26 15 79871234567 Testmelding 2 2014-08-22T16:01:10 16 79871234567 Testmelding 3 2014-08-22T16:01:10 17
Hvilket tull, sier du? Og du vil ha rett på en måte, fordi. akkurat da vi fikk vite at hvilket objekt som forlot klienten, kom det til serveren vår i form av en konvolutt i nøyaktig samme form. Riktignok ble ikke sms-meldinger serialisert i XML på den måten vi trengte - de måtte pakkes inn i elementer beskjed, ikke i Struktur. La oss nå se i hvilken form et slikt objekt kommer til metoden Send tekstmelding:

Object(stdClass) public "messageList" => object(stdClass) public "message" => objekt(stdClass) public "Struct" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (lengde=11) offentlig "tekst" => streng "Testmelding 1" (lengde=37) offentlig "dato" => streng "2013-07-21T15:00:00.26" (lengde=22) offentlig " type" => streng "15" (lengde=2) 1 => objekt(stdClass) public "phone" => streng "79871234567" (lengde=11) offentlig "tekst" => streng "Testmelding 2" (lengde= 37) offentlig "dato" => streng "2014-08-22T16:01:10" (lengde=19) offentlig "type" => streng "16" (lengde=2) 2 => objekt(stdClass) offentlig "telefon " => streng "79871234567" (lengde=11) offentlig "tekst" => streng "Testmelding 3" (lengde=37) offentlig "dato" => streng "2014-08-22T16:01:10" (lengde= 19) offentlig "type" => streng "17" (lengde=2)
Hva gir denne kunnskapen oss? Bare at banen vi har valgt ikke er riktig og vi har ikke fått svar på spørsmålet - "Hvordan kan vi få riktig datastruktur på serveren?". Men jeg foreslår at du ikke fortviler og prøver å tilpasse vårt utvalg til typen en gjenstand:

$req->messageList->message = (objekt)$req->messageList->melding;
I dette tilfellet vil vi motta en ny konvolutt:

79871234567 Testmelding 1 2013-07-21T15:00:00.26 15 79871234567 Testmelding 2 2014-08-22T16:01:10 16 79871234567 Testmelding 3 2014-08-22T16:01:10 17
Kom inn i metoden Send tekstmelding objektet har følgende struktur:

Object(stdClass) public "messageList" => objekt(stdClass) public "message" => objekt(stdClass) public "BOGUS" => array (størrelse=3) 0 => objekt(stdClass) public "phone" => streng "79871234567" (lengde=11) offentlig "tekst" => streng "Testmelding 1" (lengde=37) offentlig "dato" => streng "2013-07-21T15:00:00.26" (lengde=22) offentlig " type" => streng "15" (lengde=2) 1 => objekt(stdClass) public "phone" => streng "79871234567" (lengde=11) offentlig "tekst" => streng "Testmelding 2" (lengde= 37) offentlig "dato" => streng "2014-08-22T16:01:10" (lengde=19) offentlig "type" => streng "16" (lengde=2) 2 => objekt(stdClass) offentlig "telefon " => streng "79871234567" (lengde=11) offentlig "tekst" => streng "Testmelding 3" (lengde=37) offentlig "dato" => streng "2014-08-22T16:01:10" (lengde= 19) offentlig "type" => streng "17" (lengde=2)
Når det gjelder meg, så "fra en endring i stedene for vilkårene, endres ikke summen" (c). Hva TULL, hva Struktur Vi har ikke nådd målet vårt ennå! Og for å oppnå det, må vi sørge for at i stedet for disse uforståelige navnene, vår innfødte beskjed. Men hvordan man oppnår dette, vet ikke forfatteren ennå. Derfor er det eneste vi kan gjøre å kvitte oss med den ekstra beholderen. Med andre ord skal vi nå sørge for at i stedet for beskjed ble til TULL! For å gjøre dette, endre objektet som følger:

// opprett et objekt som skal sendes til serveren $req = new Request(); $msg1 = ny melding(); $msg1->phone = "79871234567"; $msg1->text = "Testmelding 1"; $msg1->date = "2013-07-21T15:00:00.26"; $msg1->type = 15; $msg2 = ny melding(); $msg2->phone = "79871234567"; $msg2->text = "Testmelding 2"; $msg2->date = "2014-08-22T16:01:10"; $msg2->type = 16; $msg3 = ny melding(); $msg3->phone = "79871234567"; $msg3->text = "Testmelding 3"; $msg3->date = "2014-08-22T16:01:10"; $msg3->type = 17; $req->messageList = $msg1; $req->messageList = $msg2; $req->messageList = $msg3; $req->messageList = (objekt)$req->messageList;
Hva om vi er heldige og det riktige navnet kommer opp fra ordningen? For å gjøre dette, la oss se på konvolutten som kom:

79871234567 Testmelding 1 2013-07-21T15:00:00.26 15 79871234567 Testmelding 2 2014-08-22T16:01:10 16 79871234567 Testmelding 3 2014-08-22T16:01:10 17
Ja, miraklet skjedde ikke! TULL- vi vinner ikke! Kom inn Send tekstmelding objektet i dette tilfellet vil se slik ut:

Object(stdClass) public "messageList" => object(stdClass) public "BOGUS" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (length=11) public " text" => streng "Testmelding 1" (lengde=37) offentlig "date" => streng "2013-07-21T15:00:00.26" (lengde=22) offentlig "type" => streng "15" (lengde =2) 1 => objekt(stdClass) public "phone" => streng "79871234567" (lengde=11) offentlig "tekst" => streng "Testmelding 2" (lengde=37) offentlig "dato" => streng " 2014-08-22T16:01:10" (lengde=19) offentlig "type" => streng "16" (lengde=2) 2 => objekt(stdClass) offentlig "telefon" => streng "79871234567" (lengde= 11) offentlig "tekst" => streng "Testmelding 3" (lengde=37) offentlig "dato" => streng "2014-08-22T16:01:10" (lengde=19) offentlig "type" => streng " 17" (lengde=2)
Som de sier - "Nesten"! På dette (litt triste) notatet foreslår jeg å i det stille runde av og trekke noen konklusjoner for oss selv.

8 Konklusjon

Endelig kom vi hit! La oss bestemme hva du kan gjøre nå:
  • du kan skrive den nødvendige WSDL-filen for din webtjeneste;
  • du kan skrive din egen klient uten problemer som kan kommunisere med serveren ved hjelp av SOAP-protokollen;
  • du kan skrive din egen server som kommuniserer med omverdenen via SOAP;
  • du kan sende arrays av samme type objekter til serveren fra klienten din (med noen begrensninger).
Vi gjorde også noen oppdagelser for oss selv under vår lille forskning:
  • den opprinnelige klassen SoapClient vet ikke hvordan man korrekt serialiserer datastrukturer av samme type i XML;
  • når du serialiserer en matrise til XML, oppretter den et ekstra element kalt Struktur;
  • når du serialiserer et objekt til XML, oppretter det et ekstra element kalt TULL;
  • TULL mindre ondskap enn Struktur på grunn av det faktum at konvolutten er mer kompakt (ingen ekstra navneområder legges til i XML-overskriften til konvolutten);
  • Dessverre validerer ikke SoapServer-klassen automatisk konvoluttdataene med vårt XML-skjema (kanskje andre servere ikke gjør det heller).

Hva er SOAP?

SOAP står for Simple Object Access Protocol (Simple Object Access Protocol). Jeg håper du etter å ha lest artikkelen bare blir forvirret: "Hva er dette merkelige navnet?"

SOAP i sin nåværende form er en metode for ekstern prosedyrekalling (RPC) over et nettverk. (Ja, det brukes også til å sende dokumenter som XML, men vi hopper over det for nå.)

La oss finne ut av det. Tenk deg at du har en tjeneste som returnerer en aksjekurs for en gitt ticker (aksjesymbol). Den sender data til Nasdaq-siden og genererer ønsket resultat basert på returnert HTML. Videre, for å la andre utviklere bruke den i applikasjonene sine, gjør du denne tjenesten til en komponent som finner informasjon om sitater via Internett. Det fungerer utmerket helt til Nasdaq en dag endrer oppsettet på sidene deres. Du må se gjennom hele logikken til komponenten og sende oppdateringer til alle utviklere som bruker den. Og de må på sin side sende oppdateringer til alle brukerne sine. Hvis dette skjer mer eller mindre regelmessig, kan du få mange fiender blant dine medutviklere. Og med programmerere, som du vet, er vitser dårlige. Du vil vel ikke få et bilde av favorittkatten din ut av makuleringsmaskinen i morgen?

Hva å gjøre? La oss se ... alt du trenger er å gi en funksjon som tar en ticker (av typen streng) som input og returnerer en aksjekurs (av typen flytende eller dobbel). Så ville det ikke vært enklere å bare la utviklerne på en eller annen måte kalle denne funksjonen over nettet? Utmerket! Det er også nyheter for meg, det er COM og Corba, og Java, som har gjort dette i årevis ... det som er sant er sant, men disse metodene er ikke uten feil. Ekstern COM-konfigurasjon er ikke triviell. I tillegg må du åpne så mange porter i brannmuren at du ikke kan lagre nok øl til systemadministratoren. Ja, og du må glemme brukere av alle operativsystemer unntatt Windows. Men tross alt er Linux-brukere også noen ganger interessert i utvekslingen.

Alt er imidlertid ikke tapt for Linux-brukere hvis de bruker DCOM, mer her: http://www.idevresource.com/com/library/res/articles/comonlinux.asp.

Jeg kan ikke si så mye om Corba og Java, så som en øvelse foreslår jeg at leserne finner ulempene ved disse tilnærmingene.

SOAP er en standard som lar deg beskrive en slik fjernsamtale og i hvilken form resultatet vil bli returnert. Dermed må du hoste funksjonen din i en applikasjon som er tilgjengelig over nettverket og motta anrop i form av SOAP-pakker. Etter det validerer du inndataene, kjører funksjonen din og returnerer resultatet i en ny SOAP-pakke. Hele prosessen kan kjøres over HTTP, så du trenger ikke å åpne en haug med porter i brannmuren. Er det enkelt?

Hva handler denne artikkelen om

Dette er den første i en serie artikler om SOAP som vi skriver hos Agni Software. I denne artikkelen vil jeg prøve å gi deg en ide om hva SOAP er og hvordan du skriver en applikasjon som kommuniserer med en SOAP-server.

Såpe og XML

Hvis SOAP fortsatt virker enkelt for deg, la oss legge til XML. Nå, i stedet for et funksjonsnavn og parametere, får vi en ganske kompleks XML-konvolutt, som om den er designet for å forvirre deg. Men ikke bli redd. Det kommer mer, og du må se hele bildet for å forstå kompleksiteten til SOAP.
Hvis du ikke vet hva XML er, les først XML-artikkelen min her: http://www.agnisoft.com/white_papers/xml_delphi.asp.

Alle SOAP-pakker er i XML-format. Hva betyr det? La oss se. Ta en titt på denne funksjonen (Pascal):
funksjon GetStockQuote(Symbol: streng): dobbel; Ser bra ut, men problemet er at det er Pascal. Hva er bruken av denne enkle definisjonen for en Java-utvikler? Eller for noen som jobber med VB? Vi trenger noe som alle kan forstå, også VB-programmerere. Så gi dem XML som inneholder den samme informasjonen (parametere, aksjekurser osv.). Du lager en SOAP-pakke, som i hovedsak er et kall til funksjonen din, pakket inn i XML slik at enhver applikasjon på hvilken som helst plattform kan forstå den. La oss nå se hvordan SOAP-anropet vårt ser ut:
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">


IBM


Informativ, ikke sant? SOAP blir forenklet foran øynene våre. Ok, vitser til side. Nå skal jeg prøve å forklare deg hvordan du forstår denne SOAP-samtalen.

Tag-dekryptering

Den første merkelappen som fanger oppmerksomheten din er . Denne taggen er den ytre omslaget til SOAP-pakken, og inneholder noen få navneområdeerklæringer som er av liten interesse for oss, men som er svært viktige for ethvert programmeringsspråk eller parser. Navneområder er definert slik at påfølgende prefikser som "SOAP-ENV:" eller "xsd:" aksepteres av parseren.

Neste merke er . (Vi har utelatt en kode som ikke er representert her - . Det er ikke i dette spesielle eksemplet, men hvis du vil lese mer om det, sjekk SOAP-spesifikasjonen her: http://www.w3.org/TR/SOAP/). stikkord faktisk inneholder et SOAP-anrop.

Den neste taggen i listen er − . Tagnavnet, GetStockQuote, er funksjonen som skal kalles. I følge SOAP-terminologien kalles dette en operasjon. Dermed er GetStockQuote operasjonen som skal utføres. ns1 er navneområdet som peker til urn:xmethods-quotes i vårt tilfelle.

En sidenotat om navnerom: Et navneområde lar deg kvalifisere en XML-tag. Du kan for eksempel ikke ha to variabler med samme navn i samme prosedyre, men hvis de er i to forskjellige prosedyrer er det ikke noe problem. Dermed er en prosedyre et navneområde, siden alle navn i den er unike. På samme måte er XML-tagger omfattet av navneområder, så gitt et navneområde og et tagnavn kan man identifisere det unikt. Vi vil definere et navneområde som en URI for å skille vår NS1 fra imitatorer. I eksemplet ovenfor er NS1 et alias som peker på urn:xmethods-quotes.

Legg også merke til encodingStyle-attributtet - dette attributtet spesifiserer hvordan SOAP-anropet serialiseres.

Inne i merkelappen inneholder parametere. I vårt enkleste tilfelle har vi bare én parameter - taggen . Legg merke til denne linjen ved siden av taggen:
xsi:type="xsd:streng"
Dette er omtrent hvordan XML definerer typer. (Merk hvor smart jeg brukte ordet "omtrent" når jeg generaliserte om teknologi, som kan endre seg når artikkelen er publisert.) Hva betyr dette: typen som er definert i xsi-navneområdet, som du legger merke til er definert i taggen – xsd:streng. Og dette er i sin tur en streng definert i xsd-navneområdet, igjen definert tidligere. (Jeg er sikker på at advokater ville bli begeistret av alt dette).

Inne i merkelappen "IBM" er oppført. Dette er verdien av symbolparameteren til GetStockQuote-funksjonen.

Vel, til slutt, som anstendige mennesker, stengte vi alle taggene.

Så vi fant ut SOAP-pakken som definerer kallet til SOAP-serveren. Og SOAP-serveren, ved hjelp av XML-parsere, en rød knapp og MIR-romstasjonen, dekoder denne samtalen og fastslår at du trenger en aksjekurs. Den finner umiddelbart det nødvendige tilbudet og returnerer det til deg i dette skjemaet:
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>


34.5


Etter å ha pakket ut SOAP-konvolutten, revet av båndene og raslet i omslaget, får vi vite at prisen på en IBM-aksje er 34,5.

De fleste kommersielle servere ville returnert mye mer informasjon, for eksempel i hvilken valuta og til hvilken pris den siste aksjen ble kjøpt. Og aksjekursen ville kanskje vært mer presis.

På denne måten vet vi hva SOAP-serveren forventer og hva den vil returnere. Så HVORDAN sender du denne informasjonen? Enhver transport kan brukes. Den mest opplyste er HTTP. Jeg vil ikke gå inn på detaljene i HTTP, for de som ikke vet, det er det nettleseren din bruker for å kommunisere med nettstedene du besøker.

Den ønskede HTTP-forespørselen vil se omtrent slik ut:
POST /StockQuote HTTP/1.1
Vert: www.stockquoteserver.com

Innhold-Lengde: nnnn
SOAPAction: "Some-URI"

Såpeforespørselspakken her... Den eneste andre tingen å merke seg er SOAPAction-overskriften. Denne overskriften angir formålet med forespørselen og er påkrevd. Hver SOAP-server kan ha et ubegrenset antall funksjoner og kan bruke SOAPAction-overskriften til å bestemme hvilken funksjon som kalles. Brannmurer og multipleksere kan også filtrere innhold basert på denne overskriften.

SOAP-svaret fra HTTP-serveren vil se slik ut:
HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Innhold-Lengde: nnnn

Såperesponspakke her... Hvorfor HTTP? For det første trenger ikke nettverksadministratorer å åpne mange separate porter for SOAP-anrop... webserveren kan håndtere anropene i fred, fordi Port 80 er vanligvis åpen for alle for å motta innkommende forespørsler. En annen fordel er utvidbarheten til webservere som bruker CGI, ISAPI og andre native moduler. Denne utvidelsesmuligheten lar deg skrive en modul som håndterer SOAP-forespørsler uten å påvirke annet nettinnhold.

Det er alt

Jeg håper denne artikkelen har bidratt til å kaste lys over SOAP. Hvis du fortsatt er her og vil lese mer om dette emnet, besøk forfatterens nettsted: http://www.agnisoft.com/soap

Lyrisk del.

Tenk deg at du har implementert eller implementerer et bestemt system som skal være tilgjengelig fra utsiden. De. det er en viss server du må kommunisere med. For eksempel en webserver.

Denne serveren kan utføre mange handlinger, jobbe med databasen, utføre noen tredjepartsforespørsler til andre servere, gjøre noen beregninger, etc. leve og muligens utvikle i henhold til hans velkjente scenario (dvs. i henhold til scenariet til utviklerne). Det er ikke interessant for en person å kommunisere med en slik server, fordi han kanskje ikke kan/vil gi vakre sider med bilder og annet brukervennlig innhold. Den er skrevet og fungerer og utsteder data til forespørsler om den, uten å bry seg om at de er lesbare for mennesker, klienten vil håndtere dem selv.

Andre systemer som får tilgang til denne serveren, kan allerede etter eget skjønn disponere dataene mottatt fra denne serveren - behandle, akkumulere, utstede til sine klienter, etc.

Vel, et av alternativene for å kommunisere med slike servere er SOAP. SOAP XML meldingsprotokoll.

Praktisk del.

En webtjeneste (det er det serveren leverer og det klientene bruker) gjør det mulig å kommunisere med serveren i godt strukturerte meldinger. Faktum er at webtjenesten ikke godtar noen data. Alle meldinger som ikke samsvarer med reglene vil bli returnert av webtjenesten med en feil. Feilen vil for øvrig også være i form av xml med en klar struktur (som ikke kan sies sant om teksten i meldingen).

WSDL (Web Services Description Language). Reglene som meldinger er komponert etter for nettjenesten er også beskrevet ved hjelp av xml og har også en tydelig struktur. De. hvis en webtjeneste gir muligheten til å kalle en metode, må den tillate klienter å finne ut hvilke parametere som brukes for denne metoden. Hvis webtjenesten forventer en streng for Metode1-metoden som en parameter, og strengen må hete Param1, vil disse reglene spesifiseres i webtjenestebeskrivelsen.

Ikke bare enkle typer, men også objekter, samlinger av objekter kan sendes som parametere. Beskrivelse av objektet er redusert til beskrivelsen av hver komponent av objektet. Hvis objektet består av flere felt, er hvert felt beskrevet, hvilken type det har, navnet (hva er de mulige verdiene). Felt kan også være av kompleks type, og så videre, inntil beskrivelsen av typene avsluttes med enkle - streng, boolsk, tall, dato... Noen spesifikke typer kan imidlertid vise seg å være enkle, det er viktig at klienter kan forstå hvilke verdier som kan inneholdes i dem.

For klienter er det nok å kjenne nettadressen til nettjenesten, wsdl vil alltid være i nærheten, slik at du kan få en ide om metodene og deres parametere som denne nettjenesten gir.

Hva er fordelene med alle disse klokkene og fløyter:

  • I de fleste systemer skjer beskrivelsen av metoder og typer automatisk. De. det er nok for en programmerer på serveren å si at denne metoden kan kalles gjennom en webtjeneste, og wsdl-beskrivelsen genereres automatisk.
  • En beskrivelse som har en klar struktur kan leses av enhver såpeklient. De. Uansett hva webtjenesten er, vil klienten forstå hvilke data webtjenesten godtar. I henhold til denne beskrivelsen kan klienten bygge sin egen interne struktur av objektklasser, den såkalte. binding" og. Som et resultat må programmereren som bruker webtjenesten skrive noe sånt som (pseudokode):

    NewUser:=TSoapUser.Create("Vasya","Pupkin","admin"); soap.AddUser(NewUser);

  • Automatisk validering.

    • xml-validering. xml må være godt utformet. ugyldig xml - umiddelbart en feil for klienten, la ham finne ut av det.
    • skjemavalidering. xml må ha en viss struktur. xml samsvarer ikke med skjemaet - umiddelbart en feil til klienten, la ham finne ut av det.
    • datavalidering utføres av såpeserveren slik at datatypene og restriksjonene samsvarer med beskrivelsen.
  • Autorisasjon og autentisering kan implementeres med en egen metode. innfødt. eller bruke http-autorisasjon.
  • Webtjenester kan fungere både over såpeprotokollen og over http, det vil si gjennom get-forespørsler. Det vil si at hvis enkle data (uten struktur) brukes som parametere, kan du ganske enkelt kalle den vanlige get www.site.com/users.asmx/GetUser?Name=Vasia eller post. Dette er imidlertid ikke alltid og overalt.
  • ... se wikipedia

Det er mange ulemper også:

  • Urimelig stor meldingsstørrelse. Vel, her er selve naturen til xml slik at formatet er overflødig, jo flere tagger, jo mer ubrukelig informasjon. Pluss såpe bidrar til redundansen. For intranettsystemer er problemet med trafikk mindre akutt enn for internett, så såpe for lokale nettverk er mer etterspurt, spesielt Sharepoint har en såpe-webtjeneste som du kan kommunisere med suksess (og noen begrensninger).
  • Automatisk endring av webtjenestebeskrivelse kan ødelegge alle klienter. Vel, det er som for ethvert system, så hvis bakoverkompatibilitet med gamle metoder ikke støttes, vil alt falle av ...
  • Ikke et minus, men en ulempe. Alle metodekallhandlinger må være atomære. For eksempel, når vi jobber med en subd, kan vi starte en transaksjon, utføre flere spørringer og deretter rulle tilbake eller forplikte oss. Det er ingen transaksjoner i såpe. En forespørsel, ett svar, samtalen er over.
  • Å forholde seg til beskrivelsen av hva som er på serversiden (er alt beskrevet riktig av meg?), Hva er på klienten (hva ble skrevet til meg her?) Kan være ganske vanskelig. Det var flere ganger da jeg måtte forholde meg til klientsiden og overbevise serverprogrammereren om at han hadde feilaktig beskrevet dataene, men han kunne ikke forstå noe i dem i det hele tatt, fordi automatisk generering og han, som det var, ikke burde, dette er et spørsmål om programvare. Og feilen var naturlig nok i koden til metoden, programmereren så den rett og slett ikke.
  • Praksis viser at utviklere av webtjenester er fryktelig langt unna de som bruker disse webtjenestene. Som svar på enhver forespørsel (gyldig fra utsiden), kan en uforståelig feil "Feil 5. Alt er dårlig" komme. Alt avhenger av utviklernes samvittighet :)
  • Jeg husket sikkert ikke noe...

Som et eksempel er det en åpen belavia-netttjeneste:

  • http://86.57.245.235/TimeTable/Service.asmx - inngangspunkt, det er også en tekstbeskrivelse av metoder for tredjepartsutviklere.
  • http://86.57.245.235/TimeTable/Service.asmx?WSDL - wsdl beskrivelse av metoder og typer mottatte og returnerte data.
  • http://86.57.245.235/TimeTable/Service.asmx?op=GetAirportsList - beskrivelse av en spesifikk metode med et eksempel på typen xml-forespørsel og xml-svar.

Du kan manuelt opprette og sende en forespørsel som:

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

svaret vil være:

HTTP/1.1 200 OK Dato: Man, 30 Sep 2013 00:06:44 GMT Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET X-AspNet-Versjon: 4.0.30319 Cache-kontroll: privat, maks. -age=0 Content-Type: text/xml; charset=utf-8 Content-Length: 2940

ZY Tidligere ble Aeroflot-netttjenesten åpnet, men etter at 1C la til støtte for såpe i 8ku, installerte en haug med 1c beta-testere den. Nå har noe endret seg der (jeg vet ikke adressen, du kan søke hvis du er interessert).
ZZY Ansvarsfraskrivelse. Han snakket på husstandsnivå. Du kan drikke.

Generelt er det i dag standard XML-datautvekslingsprotokoller:

  • XML-RPC- du sender en pakke og spesifiserer hvilken metode på serveren du vil ringe.
  • HVILE- det er noen objekter på serveren. Hvert objekt er preget av en identifikator. Hvert element har sin egen url. Med hvilket som helst element kan du gjøre: sette inn, slette, oppdatere, velge. Du sender ganske enkelt ønsket forespørsel til serveren (sett inn for eksempel et slikt og et slikt element). Klient-server-utvekslingen er basert på enten JSON eller XML.

SOAP er basert på RPC (Service Oriented Architecture, et sett med løst koblede tjenester som samhandler med hverandre). Den største fordelen med RPC er den lille mengden nettverksressurser (inngangspunkter) og de mange metodene som er involvert. Til tross for denne fordelen er RPC en utdatert protokoll som har en rekke ulemper:

  • Du kan ikke validere XML-RPC-meldingen. Den gamle protokollen ble laget før skjemaer (datavalideringsmetoder) ble standardisert i XML. De. serveren godtar forespørsler, den må sørge for at disse forespørslene er for den, og at dataene ikke er inkonsekvente. I XML-RPC er datatyper deklarert for dette, men dette er en datatypesjekk, og datakonsistens er ikke kontrollert (at du har mottatt en struktur med alle nødvendige parametere).
  • Du kan ikke lage kombinerte meldinger.
  • Du kan ikke bruke plass og tid (dukket opp etter opprettelsen av RPC).
  • Du kan ikke utvide meldingen, dvs. legge til tilleggsinformasjon.

Alle disse manglene er løst i XML Schema. Dette er industristandarden for å beskrive et XML-dokument. De. det er en måte å modellere vilkårlige data på. Et XML-skjema kan beskrive en modell (forhold mellom elementer og attributter og deres struktur), datatyper (karakteriserer datatyper) og vokabular (navn på elementer og attributter).

Basert på alle manglene ved XML-RPC, laget de SOAP-protokollen.

SÅPE(Simle Object Access Protocol) - protokoll for tilgang til et objekt (inngangspunkt). I dag er det den viktigste industristandarden for å bygge distribuerte applikasjoner.

Det er en utvidelse av XML-RPC-språket. De. den er bygget på prinsippet: 1 inngangspunkt og eventuelle metoder. Selve protokollen når det gjelder transport (hvordan overføre data) gir et bredt utvalg: SMTP, FTP, HTTP, MSMQ.

SOAP er kjernen i implementeringen av XML Web Services (XML Web Services). Ulempen med SOAP er at det er vanskelig å lære.

SOAP er basert på utveksling av meldinger mellom klienten og serveren (synkront og asynkront). Hver melding inneholder informasjon om dataene (hvilke data som sendes/mottas). SOAP beskriver på forhånd hele strukturen til meldingen ved hjelp av XML-skjemaer: hva skal være i meldingen, hvordan den skal overføres. Dette gjør det mulig, uten å kjenne serveren, å forstå hva som skjer der, og lar serveren sjekke om denne meldingen er til ham.

XML-skjema

Hensikten med et skjema er å beskrive datastrukturen, dvs. Hva vi har. Alle data er delt inn i enkle og komplekse typer (skalarer og strukturer). En enkel type (streng, tall, boolsk, dato) vil aldri inneholde noe inni. En struktur (objekt) kan inneholde egenskaper.

Grunnleggende SOAP-operasjoner

  • Ikke bare enkel klient-server informasjonsutveksling. Men den automatiske gjenkjenningen av serveren og søket etter denne serveren, dvs. klienten vet kanskje ikke engang noe om serveren. De. klienten søker først etter en server, finner passende tjenester, forstår hvilke metoder som finnes, hva som er på serveren og ringer til den.
  • Serveren publiserer informasjonen sin (plassering, hvilke metoder den støtter) slik at klienten kan finne denne serveren. Utgivelsen skjer i UDDI-katalogen.

Struktur av SOAP-meldinger:

  • SOAP Konvolutt (konvolutt) - dette inkluderer hele meldingen. Består av en overskrift og en brødtekst.
  • SOAP Header (header) - tilleggsinformasjon (autorisasjon, for eksempel).
  • SOAP Body (body) - selve budskapet.
  • SOAP Fault (feil) - en måte å overføre feil fra serveren til klienten.

WSDL

WSDL(Web Services Description Language) - Webtjenesters beskrivelsesspråk. Brukes i SÅPE. Dette er et slags dokument som beskriver alt: hvilke navneområder som ble brukt, hvilke dataskjemaer som ble brukt, hvilke typer meldinger serveren forventer fra klienten, hvilke konvolutter som tilhører hvilken metode, hvilke metoder som generelt finnes, til hvilken adresse som skal sendes, etc. Faktisk er WSDL en nettjeneste. Det er nok for klienten å studere innholdet i dette dokumentet, han vet allerede alt om serveren.

Enhver server bør publisere WSDL.

WSDL består av blokker:

  • Definisjonen av selve tjenesten, dvs. inngangspunkt, er porten spesifisert.
  • Metodeformat. Inngangspunktet er bundet til operasjoner, dvs. hvilke metoder den støtter. Angi anropstype, overføringsmetode. Inne i hver metode er det en forklaring – i hvilken form dataene overføres – i form av SOAP.
  • Bindingsmetoder til en melding.
  • Beskrivelse av selve meldingene.

Ansvarsfraskrivelse:Det er skrevet mange artikler om dette emnet, og som du selvfølgelig gjettet, er dette en annen. Kanskje du vil lære noe nytt av det, men ingenting topphemmelig som du ikke kunne google på egen hånd er ikke beskrevet her. Kun notater fra personlig erfaring.

Introduksjon

Vi vil kun vurdere situasjonen når det er en tredjeparts webtjeneste og oppgaven er å etablere datautveksling.

Strukturen til tjenesten er beskrevet i filen WSDL(eng. Web Services Description Language)

Filen åpnes oftest via en lenke der inngangspunktet til selve webtjenesten ligger. Jeg skrev «oftest» fordi det finnes unntak. For eksempel publiserer ikke en SAP-basert webtjeneste en wsdl og kan kun hentes fra selve applikasjonen.

Og så har vi en beskrivelse av webtjenesten, pålogging, passord. La oss koble til.

// Definer innstillingene for ServiceNamespace URL = "http://Somesite.ru"; Brukernavn = "TestBruker"; Passord = "q1w2e3"; LocationWSDL = "https://Somesite.ru/WebService/Some?wsdl"; ServiceName = "Noen Tjenestenavn"; ConnectionPointName = "SomeService_Port"; // Opprett en SSL-tilkobling = New SecureConnectionOpenSSL(); WSDefinition = New WSDefinition(LocationWSDL,SSL); WSProxy = New WSProxy(WSDefinition, ServiceNamespace URL, ServiceName, ConnectionPointName, SSL); WSProxy.User = Brukernavn; WSProxy.Password = Passord;

Utmerket! Vi har koblet til nettjenesten! I teorien er dette grunnlaget for ethvert byttealternativ, da det lar deg lage datastrukturobjekt basert på wsdl, og det er en glede å jobbe med et slikt objekt.

Tenk på XML som SoapUI gir oss

357 121212 M 19900111 Mercedes GLS Audi TT

La oss nå beskrive det programmatisk

// Lag et objekt og fyll det med data OwnXDTOFactory = WSDefinition.XDTOFactory; RootType = OwnFactoryXDTO.Type(URLServiceNamespace, "SUBMISSION"); RootObject = OwnFactoryXDTO.Create(RootType); RootObject.ID = "4356"; ClientType = OwnFactoryXDTO.Type(URLServiceNamespace, "CUSTOMER"); ClientObject = OwnFactoryXDTO.Create(ClientType); ClientObject.CLIENT_ID = "121212"; ClientObject.SEX = "M"; // F - kvinne, M - mann ClientObject.CLIENT_BIRTHDAY = "19900111"; // Customer Cars AutoType = CustomFactoryXDTO.Type(URLServiceNamespace, "CARS"); AutoObject = OwnFactoryXDTO.Create(AutoType); AutoObject.CLASS = "Mercedes"; AutoObject.MODEL = "GLS"; ClientObject.CARS.Add(AutoObject); AutoObject = OwnFactoryXDTO.Create(AutoType); AutoObject.CLASS = "Audi"; AutoObject.MODEL = "TT"; ClientObject.CARS.Add(AutoObject); RootObject.CUSTOMER.Add(ClientObject);

Data fullført. Nå må vi sende dem.

Akkurat i dette øyeblikket oppstår mange nyanser. La oss prøve å vurdere hver enkelt.

Oppskrift 1. Sending av hele XDTO-objektet

Resultat = WSProxy.AddCustomers(RootObject);

Det gjenstår bare å behandle resultatet at tjenesten returnerte til oss og det er det. Enig i at det er veldig praktisk!

Men i praksis er det ikke alltid slik. For eksempel kommer 1c ikke overens med å prefiksere visse tagger i xml når navneområdet til rotkoden er forskjellig fra det til underkodene. I slike tilfeller må du samle såpe manuelt. Jeg måtte også forholde meg til webtjenester som forventer ren xml som parameter. Galskap, men det er likevel ikke så vanskelig å gjøre.

Oppskrift 2. Sender ren xml som parameter

XMLRecordParameters = NewXMLRecordParameters("UTF-8", "1.0", True); MyXML = Ny XMLWriter; MyXML.SetString(XMLRecordParameters); MyXML.WriteDeclarationXML(); CustomXDTOFactory.WriteXML(MyXML, RootObject); StringXML = MyXML.Close(); If DeleteNamespaceDescription Then AttemptFirstTagInString = StrGetString(XMLString,2); RootTagName = RootObject.Type().Name; XMLString = StrReplace(XMLString, FirstTagInString, "<"+ИмяКорневогоТэга+">"); Unntak //ErrorDescription() EndTry; EndIf; Result = WSProxy.AddCustomers(XML-streng);

Hvis du ikke fjerner navneområdet som 1s legger til som standard, har det blitt mer enn bare 5 linjer med kode. Mesteparten av tiden pakker jeg inn xml-transformasjonen i en funksjon, siden vi vanligvis kaller mer enn én metode.

Oppskrift 3. Send via opprinnelig HTTP-forespørsel.

SÅPEstreng = " | | |" +StringXML+ " | |"; // Beskriver HTTP-forespørselshoder 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(Brukernavn, Passord)); // OBS!!! // Du kan ikke programmere fylle ut følgende overskrifter, fordi dette fører til en feil // Plattformen vil fylle dem ut riktig //Headers.Insert("Accept-Encoding", "gzip,deflate"); //Headers.Insert("Content-Length", Format(StringLength( SOAP String)," HG=")); // meldingslengde //Headers.Insert("Host", "Somesite.ru:8001"); //Headers.Insert("Connection", "Keep-Alive") ; //Headers. Insert("User-Agent", "Apache-HttpClient/4.1.1 (java 1.5)"); // Koble til nettstedet. Connection = New HTTPConnection("Somesite.ru/WebService/Some", Brukernavn, Passord, SSL, falsk); // Adressen må være uten https:// // Få teksten til rotsiden via en POST-forespørsel. c = New HTTPRequest("/GetCustomer", Headers); HTTPRequest.SetBodyFromString(SOAPString); Resultat = Connection.CallHTTPMethod("POST", HTTPRequest);

I dette alternativet må vi bygge såpe manuelt. I hovedsak pakker vi ganske enkelt inn xml-en fra oppskrift 2 i en såpeinnpakning, der vi, avhengig av nettjenestens krav, kan endre såpen vår til vårt hjerte.

Deretter beskriver vi overskriftene i henhold til dokumentasjonen. Noen tjenester vil lett tygge forespørselen vår uten overskrifter, her må du se på en spesifikk sak. Hvis du ikke vet hvilke overskrifter du skal foreskrive, er den enkleste måten å se forespørselen i SoapUI ved å bytte til RAW-fanen.

Funksjonen for å få Base64-strengen ser slik ut (kikket):

Funksjon GetBase64AuthorizationHeader(Brukernavn, Passord) FileEncoding = TextEncoding.UTF8; TempFile = GetTemporaryFileName(); Record = New TextWrite(TemporaryFile, FileEncoding); Write.Write(Brukernavn+":"+Passord); Record.Close(); BinData = New BinaryData(TempFile); Resultat = Base64String(DvData); DeleteFiles(TempFile); Resultat = Gj.sn.(Resultat,5); Returner Resultat; EndFunctions

Det er et viktig poeng. Når du arbeider med HTTPConnection, spesifiser adressen uten å spesifisere "http://" og "https://"-protokollene, ellers risikerer du å kaste bort tid på å lete etter en uopplagt feil.

Oppskrift 4. Sending via WinHttpRequest

WinHttp = New COMObject("WinHttp.WinHttpRequest.5.1"); WinHttp.Option(2,"UTF-8"); WinHttp.Option(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("Innholdstype", "tekst/xml"); WinHttp.SetCredentials(Brukernavn, Passord, 0); WinHttp.Send(SOAP-streng); WinHttp.WaitForResponse(15); XMLResponse = WinHttp.ResponseText();

Her faktisk det samme som i forrige versjon, men vi jobber med et COMObject. Vi spesifiserer tilkoblingsstrengen i sin helhet, sammen med protokollen. Spesiell oppmerksomhet bør bare rettes mot flaggene for å ignorere feil i SSL-sertifikater. De er nødvendige hvis vi jobber over SSL, men uten et spesifikt sertifikat, siden det ikke er mulig å opprette en ny sikker tilkobling i dette alternativet (eller jeg vet ikke hvordan). Resten av mekanismen er lik den forrige.

I tillegg til "WinHttp.WinHttpRequest.5.1", kan du bruke "Microsoft.XMLHTTP", "Msxml2.XMLHTTP", "Msxml2.XMLHTTP.3.0", "Msxml2.XMLHTTP.6.0", hvis det plutselig ikke tar av på WinHttp. Metodene er nesten like, bare antall parametere er forskjellige. Jeg mistenker at ett av disse alternativene er kablet inne i 1c HTTPRequest-objektet.

For øyeblikket er dette alle oppskriftene jeg har. Kommer jeg over nye, vil jeg definitivt supplere artikkelen.

Resultatbehandling

I oppskrift 1 får vi oftest et ferdig XDTO-objekt og jobber med det som en struktur. I alle andre tilfeller kan du konvertere xml-svaret til XDTO

Hvis Result.StatusCode = 200 Da XMLReader = Ny XMLReader; ReadingXML.SetString(Result.GetBodyAsString()); ResponseObject = OwnFactoryXDTO.ReadXML(ReadingXML); Rapport(ObjectResponse.Body.Response.RESPONSE_ID); Rapport(ObjectResponse.Body.Response.RESPONSE_TEXT); Slutt om;

Alt er enkelt her.

I stedet for en konklusjon

1. Begynn å jobbe med webtjenester med SoapUI-programmet. Den er designet for slikt arbeid og lar deg raskt forstå hvordan en bestemt tjeneste fungerer. Det er en artikkel å lære

2. Hvis du bytter med en tjeneste via en usikker http-kanal og spørsmålet dukker opp om hva nøyaktig 1s sender i meldingene dine, så kan du bruke trafikksniffer som Wireshark, Fiddler og andre. Problemet oppstår bare hvis du bruker en ssl-tilkobling.

3. Hvis nettjenesten likevel kommuniserer via https, installerer vi Nginx-serveren på en ekstern maskin (hvilken som helst, viktigst av alt, ikke på egen hånd), som vi vil kontakte, og den vil på sin side pakke alt inn https og send det til rett sted ( omvendt proxy ) og legg til standardkonfigurasjonen:

Server ( lytt 0.0.0.0:8080; servernavn MyServer; plassering ~ .* ( proxy_pass https://Somesite.ru:8001; proxy_set_header Host $host; proxy_set_header Autorisasjon "Basic "; proxy_pass_header Autorisasjon; ) )

5. Hvis autentisering involverer bruk av informasjonskapsler, ble følgende funnet

P.S. Hvis du har spørsmål, forslag til forbedring av koden, har dine egne oppskrifter som skiller seg fra de som er beskrevet, du finner feil eller tror at forfatteren er "feil" og han "hører ikke hjemme i 1-er", så skriv kommentarer så diskuterer vi alt.