Casa / Mezzi sociali / 1c esempio di utilizzo delle intestazioni di richiesta http

1c esempio di utilizzo delle intestazioni di richiesta http

Durante lo sviluppo della procedura per l'invio di informazioni al sito da 1C con piattaforma versione 8.3.9.2170, mi sono imbattuto in un problema: lo sviluppatore del sito mi ha dato la possibilità di registrare le informazioni necessarie solo utilizzando una richiesta HTTP utilizzando il metodo PUT.

Senza pensarci due volte, ho abbozzato un semplice codice:

Connessione = New HTTPConnection("www.mysite.ru"); Intestazioni = Nuova corrispondenza; Headers["Content-Type"] = "application/x-www-form-urlencoded"; Richiesta = New HTTPRequest("/api/order_items/93076?order_item=30", Headers); Connessione.Scrittura(Richiesta);

Sulla base dei risultati dell'esecuzione, la riga corrispondente dell'ordine dell'acquirente sul sito Web avrebbe dovuto indicare la quantità di merce ricevuta in magazzino.

Tuttavia, come probabilmente hai già capito, non è successo niente. Dopo essermi assicurato che non ci fossero errori sul sito (inviando una richiesta simile tramite il plug-in di Chrome), ho eseguito il mio computer locale server web e ha iniziato a sperimentare.

Venne subito alla luce una cosa strana: il codice sopra non genera una richiesta PUT, ma HEAD!

Nei log di Apache ho visto quanto segue:

127.0.0.1 - - "HEAD /api/order_items/93076?order_item=30 HTTP/1.1"

Sono rimasto un po 'sorpreso (dopotutto, era scritto nero su bianco nel manuale PUT), ma non ero perplesso - dopotutto, puoi chiamare direttamente il metodo:

Connection.CallHTTPMethod("PUT",Request);

I log sono gli stessi:

127.0.0.1 - - "HEAD /api/order_items/93076?order_item=30 HTTP/1.1"

"Forse sto facendo qualcosa di sbagliato?" - Mi sono fatto una domanda. Ma su Internet e nei manuali non c'erano indizi. Ebbene, nessuno ha ancora cancellato il metodo del poke scientifico. Per iniziare, ho provato a fare questo:

Connection.CallHTTPMethod("fwfw", Richiesta);

Nei log ho ottenuto:

127.0.0.1 - - "?????? /api/order_items/93076?order_item=30 HTTP/1.1"

Curiosamente, significa che 1C sostituisce specificamente il metodo PUT (perché non ha soddisfatto 1C?).

Dopo qualche altro tentativo, sono arrivato a questo:

Connection.CallHTTPMethod("PUT", Richiesta);

Nei log ho ottenuto:

127.0.0.1 - - "PUT /api/order_items/93076?order_item=30 HTTP/1.1"

E questa opzione ha già funzionato sul sito e tutti erano soddisfatti.

Ha suggerito una soluzione più corretta al problema: è necessario specificare il corpo della richiesta, qualsiasi, anche vuoto. Ad esempio, questo funzionerebbe:

Connessione = New HTTPConnection("www.mysite.ru"); Intestazioni = Nuova corrispondenza; Headers["Content-Type"] = "application/x-www-form-urlencoded"; Richiesta = New HTTPRequest("/api/order_items/93076?order_item=30", Headers); Request.SetBodyFromString("", TextEncoding.UTF8, UseByteOrderMark.Don't Use); Connessione.Scrittura(Richiesta);

Ed è già del tutto corretto, probabilmente, trasferire i valori dei parametri stessi nel corpo della richiesta.

La conclusione è la seguente: la piattaforma 1C considera errata una richiesta PUT senza corpo e sostituisce il metodo con HEAD.

È curioso che 1C non tenga traccia di una richiesta POST senza corpo e non la trasformi in GET, è stata verificata per motivi di interesse sportivo.

Come direbbe il noto Vovochka della famosa barzelletta: "Dov'è la logica?".

Spero che la mia pubblicazione possa far risparmiare a qualcuno qualche ora di vita in cerca di una risposta. =)))

A partire dalla seconda versione della piattaforma 8, utenti e sviluppatori hanno la possibilità di utilizzare direttamente in 1C richiesta http. Il programma supporta due tipi di richieste:

  • Richieste POSTALI;
  • OTTIENI richieste.

Pertanto, è stato creato uno strumento abbastanza conveniente per lo scambio di dati e l'interazione con servizi Web e servizi che funzionano tramite http.

OTTIENI richiesta

Naturalmente, gli esempi più semplici di utilizzo delle query illustrano le loro capacità molto meglio di molte righe di descrizione. Dunque proviamo:

  1. Ottieni il corpo della pagina principale del nostro sito;
  2. Elaboriamo il reindirizzamento della richiesta;
  3. Prenderemo la foto dal sito.

Ottenere il corpo del sito

Iniziamo in modo semplice. Sulla Fig..

Il risultato dell'esecuzione di questa sezione di codice è un testo abbastanza grande, la cui sezione finale è mostrata in Fig.2.

Fig.2

Nella prima riga di codice, creiamo un oggetto connessione con una risorsa http. Un oggetto può contenere le seguenti proprietà:

  • Server - stringa di connessione contenente l'indirizzo del server;
  • Porta - contiene un numero che indica la porta del server, per impostazione predefinita, a seconda del tipo di connessione, è possibile specificare 80 per connessioni insicure o 443 per SSL sicuro.
  • Nome utente - specificato se è richiesta l'autorizzazione sul server;
  • Password – password dell'utente sulla risorsa specificata;
  • Proxy - può contenere un oggetto di tipo InternetProxy, indicato quando si utilizza un proxy per comunicare con il server;
  • SecureConnection: il valore predefinito è FALSE, il passaggio a TRUE indica l'utilizzo del protocollo https.

Inoltre, l'oggetto HTTPConnection ha i propri metodi, il cui accesso consente di descrivere in modo più completo l'algoritmo di esecuzione del gestore:

  • CallHTTPmethod - contiene due parametri obbligatori HTTPmethod e HTTPrequest, supporta la possibilità di scrivere il corpo della risposta nel file specificato nel terzo parametro;
  • Scrivi: invia i dati al server utilizzando una richiesta PUT;
  • Modifica: modifica un oggetto elaborando le richieste PATCH;
  • SendForProcessing - il metodo che indica l'utilizzo di una richiesta POST, come in tutti i metodi precedenti, deve contenere il testo della richiesta, può anche inviare l'indirizzo del file di risposta per la scrittura dei dati;
  • Ottieni - maggiori informazioni saranno discusse di seguito;
  • GetHeaders è un altro metodo che verrà utilizzato in tutto l'articolo;
  • Delete è in realtà una richiesta Delite che rimuove la risorsa passata nella richiesta dal server.

Nella seconda riga, creiamo una richiesta al sito selezionato, il testo della nostra richiesta contiene una barra, il che significa che vogliamo ottenere pagina iniziale. Se una qualsiasi espressione segue la barra, ad esempio "page2" o "news" otterremo un'altra pagina.

La terza riga esegue la nostra richiesta al server.

Nella quarta mostriamo il risultato.

Gestione di un reindirizzamento di una richiesta http

Immagina una situazione in cui dobbiamo ottenere in modo programmatico un risultato di ricerca tramite any motore di ricerca dal tasto "Richieste in 1s". La sezione di codice necessaria per accedere a GOOGLE è mostrata in Fig. 3

Fig.3

Qui, oltre alle costruzioni a noi già familiari, ci sono Headers e StatusCode. Affrontiamoli.

StatusCode - il valore standard specificato in "Request for Comments" , può assumere i seguenti valori:

  1. Se tutto va bene, verrà restituito un valore compreso tra 100 e 299;
  2. In caso di reindirizzamento verrà restituito un codice compreso tra 300 e 399, nel nostro caso un reindirizzamento permanente riuscito alla risorsa sarà determinato dal codice 301;
  3. In caso di errori nella richiesta, il parametro assumerà un valore da 400 a 499;
  4. Un valore compreso tra 500 e 599 indica problemi con il server.

Ogni pagina ha un'intestazione, nel cui testo si possono distinguere diversi parametri (Fig. 4):

  1. Schema elettrico (tutto fino a due barre "//");
  2. barra degli indirizzi connessioni;
  3. Nome utente e password;
  4. Porta e host a cui connettersi.

È questa suddivisione che viene eseguita dalla funzione BreakAddressString. Ottenuto così un nuovo indirizzo, possiamo salvare la pagina sul nostro computer e aprirla nel browser predefinito (procedura GetPage).

Fig.5

Non ci sono nuove funzionalità e modi per lavorare con le query, stiamo effettivamente creando Documento di testo dal corpo del sito e avvia la pagina nel browser.

Inseriamo il file nella radice dell'unità D e lo chiamiamo test.

Ottenere un'immagine dal sito

Sorge spontanea una domanda: se non abbiamo bisogno dell'intero sito, ma solo dei suoi singoli elementi, è possibile farlo e come? Si, puoi. Il codice del programma che permette di fare ciò è mostrato in Fig. 6

Fig.6

Come puoi vedere dalla figura, nel corpo della richiesta abbiamo il codice dell'elemento della struttura del sito che dobbiamo ottenere. Questa parte non era nella nostra descrizione precedente e dobbiamo soffermarci su questo punto in modo più dettagliato.

Abbiamo usato il browser Opera per accedere al sito. Ha uno strumento importante per noi, quando fai clic con il pulsante destro del mouse su un elemento, puoi chiamare menù contestuale, uno dei cui elementi è "Visualizza codice elemento".

È grazie a lui che possiamo ottenere l'indirizzo che verrà utilizzato nella richiesta Fig.7.

Richiesta POSTALE

A differenza delle semplici richieste Get, POST richieste http hanno un corpo di testo che può essere memorizzato sia in forma di testo normale che come file con estensioni xml, soap, json. La rete dispone di molti strumenti per la creazione di testi di query che consentono di eseguire il debug e monitorare l'esecuzione di determinate richieste.

In 1C, per lanciare una richiesta con un testo specifico, l'oggetto richiesta HTTP ha una procedura SetBodyFromString.

Nella piattaforma 1C Enterprise 8.3, è diventato possibile creare servizi HTTP

Con l'aiuto del linguaggio integrato, è ora possibile formare una risposta alla richiesta. In questo caso, hai un comodo accesso al corpo, alle intestazioni e alla riga della fonte richiesta, ed è anche possibile generare codice, corpo e intestazioni risposta a tua discrezione.

Rispetto ai servizi web disponibili nella piattaforma SOAP, i servizi HTTP presentano una serie di vantaggi:

  • Facilità di programmazione del cliente di tali servizi;
  • Quantità potenzialmente inferiore di dati trasferiti;
  • Carico computazionale potenzialmente inferiore;
  • I servizi HTTP sono orientati alla "risorsa", mentre i servizi SOAP sono orientati all'"azione".

Il database dimostra l'implementazione dei servizi http

Elenco delle fatture del servizio http

I modelli di URL vengono utilizzati nel servizio http, viene implementata la gestione delle proprietà ParametriURL oggetto HTTPServiceRequest
IN questo esempio mostra come è possibile creare una base di posa tra la base di lavoro e il sito aziendale
Viene effettuato il collegamento alla base demo” Gestione commerciale 11“, in cui devi prima impostare una proprietà aggiuntiva con il nome Parola d'ordine web , dove memorizzeremo la password per l'accesso.
La richiesta http verrà passata nei parametri URL: TIN come login e password.
Durante l'elaborazione della richiesta, viene effettuata una connessione tramite ComConnector all'UT (i freni sono garantiti) e da lì viene effettuata una selezione
Non rivendico la velocità e la sicurezza di questa soluzione, è un esempio

COSÌ. Un nuovo ramo è apparso nell'albero dei metadati: i servizi HTTP
Noi creiamo nuovo servizio, specificarne il nome e l'URL root(elenco)
L'URL principale verrà utilizzato per chiamare il nostro servizio http
Successivamente, aggiungi un modello di URL al servizio http, specificando "/(Login)/(Password)" come modello
Tale modello consentirà, durante l'elaborazione di una richiesta http, di ottenere la struttura corrispondente dei parametri e i loro valori nei parametri URL
Ora aggiungiamo un metodo chiamato "get" al nostro modello di URL e selezioniamo GET come metodo http.
Apri il gestore e scrivi il codice
Un gestore di metodi è una funzione che deve restituire un valore di tipo HTTPServiceResponse

http serviceOrderStatus

L'esempio implementa l'elaborazione delle variabili passate dal metodo POST, la formazione di una risposta sotto forma di una pagina html.
Questa volta i dati vengono recuperati dal database in cui si trova hs, quindi funziona molto più velocemente del precedente servizio http.
Durante l'implementazione sistema di lavoro ha senso creare oggetti nel database (con il servizio) e impostare la migrazione dei dati dal database di origine (ad esempio, un separato processo di fondo). Quando si elabora una richiesta http, effettuare una selezione direttamente dal database in cui si trova.

Pubblicazione

Ci sono molte informazioni sull'installazione e la configurazione di un server web.
Ho usato build httpd-2.2.25-win32-x86-openssl-0.9.8y.exe da qui
Installato utilizzando il metodo "Next-Next-Finish" 🙂
La pubblicazione dei servizi http avviene nello stesso luogo in cui era ed è la pubblicazione dei servizi web, e non è particolarmente diversa.
Dopo aver installato il web server in modalità "Configuratore", accedere al menù "Amministrazione" - "Pubblicazione su web server"
Nella scheda "Servizi HTTP", imposta il nome di pubblicazione, il server Web, la directory di pubblicazione e contrassegna i nostri servizi (nel mio caso, il nome è "web", server Web Apache 2.2)
Durante la pubblicazione, i blocchi corrispondenti vengono scritti automaticamente nel file di configurazione httpd.conf e il server viene riavviato (alla prima pubblicazione)
Chiamare un servizio http
Esempio: http://mysite/web/hs/list, Dove
il mio sito– indirizzo del server (se il web server è installato localmente, puoi usare 127.0.0.1)
ragnatela- il nome specificato al momento della pubblicazione (alias)
hs- un segmento di percorso richiesto che dice al server che funzionerà con i servizi http
elenco– URL root del servizio web

Test

Elenco fatture

http://127.0.0.1/web/hs/list/7705260681/pswMP (Non dimenticare di impostare una proprietà aggiuntiva nell'UT per la password)

Si presuppone che per accedere al registro degli atti l'utente utilizzi un link diretto contenente TIN e password

Lo stato dell'ordine

http://127.0.0.1/web/hs/check

La richiesta e la risposta si trovano allo stesso URL. Quando si accede alla pagina, viene attivato il metodo GET, che restituisce il modulo html

Quando si fa clic su "Verifica", il numero dell'ordine viene inviato utilizzando il metodo POST allo stesso URL, la risposta viene restituita con lo stesso modulo di richiesta, integrato con i dati sull'ordine richiesto.

Nel file allegato - scarico del database per 1C 8.3. La configurazione implementa 2 servizi http (dalla pubblicazione), creando una com-connessione con la base demo UT 11, il documento "Ordine".

Cosa ti serve per iniziare e testare

  • server web
  • qualsiasi browser web
  • rilascio corrente1C: Impresa 8.3

Bene, ecco un esempio di elaborazione di un file XML con controparti lato server:

Codice VBS
require_once dirname(__FILE__) . "/../inc/initf.php" ;
classe Onec_Import_Customers(
$ istanza statica privata ;
funzione __construct()(

Self::$istanza = $questo ;

funzione pubblica processo()(
$rawHttp = file_get_contents("php://input") ;
$xml_raw = str_replace("xml=", "", $rawHttp) ;

If ($_SESSION["loggato"] || vero)(
file_put_contents("log/onec_import_customers_" .time(). ".log", "REQUEST " . print_r($_REQUEST, 1) . " SERVER " . print_r($_SERVER,1). " FILES " . print_r($_FILES, 1) .$xml_raw);
file_put_contents("log/onec_import_customers_last.log", "RICHIESTA " . print_r($_REQUEST, 1) . " SERVER " . print_r($_SERVER,1). " FILE " . print_r($_FILES,1) . $xml_raw) ;

//$xml = stripslashes($_POST["xml"]);
$xml = strisce ($xml_raw);
if(!$xml) (
$xml = $xml_raw;
//die("nessun dato XML (chiave post "xml")") ;
}
if ($this->impostaClienti($xml)) (
morire("va bene");
) altro (
morire("FALLIRE") ;
}
) altro (
morire();
}
}

Set di funzioni privateClienti($xml)(
$db = db::getInstance() ;

$sxml = simplexml_load_string($xml) ;

$clienti = $sxml->("P”PsPiPsPIRsSЂ") ? $sxml->("R”PsPiRsPIRsSЂ") : self::err("Formato file non valido. Clienti.") ;

$finale = matrice();
$k = 0 ;

$tuttiClienti = array();

Foreach ($clienti come $cust) (
$password = base::generatePassword(6,1) ;

$arr["password"] = $password ;

$arr ["email"] = (array)$cust->("Почта") ;//? (array)$cust->("PџPѕS‡S‚P°") : self::err("Formato file non valido. N. cliente:" . $k . ". Email non valida") ;
$arr["email"] = $arr["email"] ? $arr ["email"] : "";//: self::err("Formato file non valido. numero cliente:" . $k . ". Email non valida") ;

$arr ["app_name"] = (array)$cust->("НаименоваРРЅРёРµ") ;//? ;
$arr ["nome_app"] = $arr ["nome_app"] ? $arr ["app_name"] : "";//self::err("Formato file non valido. N. cliente:" . $k . ". Nome non valido") ;

$arr ["clientid"] = (array)$cust->("Номер") ? (array)$cust->("Номер") : self::err("Formato file non valido. Numero clienti:" . $k . ". Cliented non valido") ;
$arr["clientid"] = $arr["clientid"] ? $arr ["clientid"] : self::err("Formato file non valido. Clienti n.:" . $k . ". Clientid non valido") ;

$arr ["date"] = (array)$cust->("R”R°C‚R°") ? (array)$cust->("P”P°S‚P°") : self::err("Formato file non valido. Numero clienti:" . $k. ". Data non valida") ;
$arr["data"] = $arr["data"] ? $arr ["data"] : self::err("Formato file non valido. Numero clienti:" . $k . ". Data non valida" );

$arr["date"] = esplodi(".",$arr["date"]);
krssort($arr["data"]);
$arr ["data"] = implode("-",$arr ["data"]) . "00:00:00" ;

$arr ["phone_home"] = (array)$cust->("Телефон") ;//? (array)$cust->("PўPµP"PµS„PsPS") : self::err("Formato file non valido. Numero clienti:" . $k . ". Telefono non valido") ;
$arr ["phone_home"] = $arr ["phone_home"] ? $arr ["phone_home"] : "";//self::err("Formato file non valido. Numero clienti:" . $k . ". Telefono non valido") ;

$arr ["distretto"] = (array)$cust->("P P°P#PsPS") ;//? (array)$cust->("P P°P#PsPS") : self::err("Formato file non valido. Numero clienti:" . $k . ". Distretto non valido") ;
$arr ["distretto"] = $arr ["distretto"] ? $arr ["distretto"] : "";//self::err("Formato file non valido. Numero clienti:" . $k . ". Distretto non valido" );

$arr ["strada"] = (array)$cust->("PJP"PeC†P°") ;//? (array)$cust->("PJP"PoC†P°") : self::err("Formato file non valido. Numero clienti:" . $k . ". Via non valida") ;
$arr["strada"] = $arr["strada"] ? $arr ["via"] : "";//self::err("Formato file non valido. Numero clienti:" . $k . ". Via non valida") ;

$arr ["edificio"] = (array)$cust->("R”RѕRј") ;//? (array)$cust->("P”PѕРј") : self::err("Formato file non valido. Numero clienti:" . $k . ". Edificio non valido") ;
$arr["edificio"] = $arr["edificio"] ? $arr ["edificio"] : "" ;//self::err("Formato file non valido. Numero clienti:" . $k . ". Edificio non valido") ;

$arr ["appartamento"] = (array)$cust->("PљPIR°СЂС‚РёСЂР°") ;//? (array)$cust->("Квартира") : self::err("Formato file non valido. Numero clienti:" . $k . ". Appartamento non valido") ;
$arr ["appartamento"] = $arr ["appartamento"] ? $arr ["appartamento"] : "";// self::err("Formato file non valido. Numero clienti:" . $k . ". Appartamento non valido" );

$allCustomers [$arr ["clientid"]]= array("password"=>$password, "email"=>$arr ["email"]) ;

$finale = $arr;
++$k ;
}

Restituisce $this->buildCustomers($final) ;
/*
if($this->buildCustomers($final)) (
foreach ($allCustomers as $clientid=>$data) (
self::sendPasswordToMail($data["email"], $idclienti, $data["password"]) ;
}
}*/

Funzione statica privata sendPasswordToMail($email, $client_id, $password) (
$db = db::getInstance() ;
$config = modello_config::getInstance();
$lng = Richiesta::$currentLang["id"] ;
$email_text = $db->getRow("s1_text", "*", "`alias`="registration_ok" AND `lng_id`="($lng)"") ;
$corpo = str_replace("%password%", $password, $email_text["content"]) ;
$corpo = str_replace("%client_id%", $client_id, $corpo) ;
base::mailSend($body, $email_text["title"] . " - " . $config->defaultTitle("site.ru") , $email, $app["app_name"], $config->site_admin_mail( " [e-mail protetta]"), $config->from_name("site")) ;

Funzione privata buildCustomers($data)(

$db = db::getInstance() ;

$qry = "I_nsert INTO s1_customer (`active`,`password`,`app_name`,`email`,`date`,`clientid`,`phone_home`,`street`, `district`, `building`, `apartament `) VALORI " ;
foreach ($dati come $righe)(
$queryArr = "(
"0"
,MD5("($righe["password">")
,"($db->escape($rows["app_name"]))"
,"($db->escape($rows["email"]))"
,"($db->escape($rows["date"]))"
,"($db->escape($rows["clientid"]))"
,"($db->escape($rows["phone_home"]))"
,"($db->escape($rows["street"]))"
,"($db->escape($rows["distretto"]))"
,"($db->escape($rows["edificio"]))"
,"($db->escape($rows["appartamento"]))"
)" ;
}
$qry .= implode(",", $queryArr) ;
$qry .= " SU AGGIORNAMENTO CHIAVE DUPLICATA
`nome_app` = VALORI(nome_app)
,`date` = VALUES(data)
,`email` = VALORI(email)
,`phone_home` = VALUES(phone_home)
,`strada` = VALORI(strada)
,`distretto` = VALUES(distretto)
,`costruzione` = VALUES(costruzione)
,`appartamento` = VALUES(appartamento)
" ;
return $db->query($qry) ;
}

funzione statica pubblica getInstance()(
if (!self::$istanza)
{
nuovoself();
}
return self::$istanza ;

Funzione statica privata err($msg) (
lancia una nuova ImportException($msg) ;
}

La classe ImportException estende Exception(

Funzione __construct($msg)(
die ("Errore: " . $msg) ;