Maison / Réseaux sociaux / 1c exemple d'utilisation des en-têtes de requête http

1c exemple d'utilisation des en-têtes de requête http

Lors du développement de la procédure d'envoi d'informations sur le site à partir de 1C avec la version de plate-forme 8.3.9.2170, j'ai rencontré un problème: le développeur du site m'a donné la possibilité d'enregistrer les informations nécessaires uniquement à l'aide d'une requête HTTP utilisant la méthode PUT.

Sans réfléchir à deux fois, j'ai esquissé un code simple:

Connexion = Nouvelle connexion HTTP("www.monsite.ru"); En-têtes = Nouvelle correspondance ; En-têtes["Content-Type"] = "application/x-www-form-urlencoded" ; Request = New HTTPRequest("/api/order_items/93076?order_item=30", Headers); Connection.Write(Requête);

Sur la base des résultats de l'exécution, la ligne correspondante de la commande de l'acheteur sur le site Web aurait dû indiquer la quantité de marchandises reçues à l'entrepôt.

Cependant, comme vous l'avez probablement déjà compris, rien ne s'est passé. Après m'être assuré qu'il n'y avait pas d'erreurs sur le site (en envoyant une requête similaire via le plugin Chrome), j'ai couru sur mon ordinateur local serveur Web et a commencé à expérimenter.

Une chose étrange est immédiatement apparue: le code ci-dessus ne génère pas un PUT, mais une requête HEAD !

Dans les journaux Apache, j'ai vu ce qui suit :

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

J'ai été un peu surpris (après tout, c'était écrit noir sur blanc dans le manuel PUT), mais je n'étais pas perdu - après tout, vous pouvez appeler la méthode directement :

Connection.CallHTTPMethod("PUT",Request);

Les journaux sont les mêmes :

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

« Peut-être que je fais quelque chose de mal ? - Je me suis posé une question. Mais sur Internet et dans les manuels, il n'y avait aucun indice. Eh bien, personne n'a encore annulé la méthode du poke scientifique. Pour commencer, j'ai essayé de faire ceci :

Connection.CallHTTPMethod("fwfw", Request);

Dans les logs j'ai :

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

Curieusement, cela signifie que 1C remplace spécifiquement la méthode PUT (pourquoi n'a-t-il pas plu à 1C ?).

Après quelques essais supplémentaires, je suis arrivé à ceci:

Connection.CallHTTPMethod("PUT", Requête);

Dans les logs j'ai :

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

Et cette option a déjà fonctionné sur le site et tout le monde était satisfait.

Il a suggéré une solution plus correcte au problème : vous devez spécifier le corps de la requête, quelconque, même vide. Par exemple, cela fonctionnerait :

Connexion = Nouvelle connexion HTTP("www.monsite.ru"); En-têtes = Nouvelle correspondance ; En-têtes["Content-Type"] = "application/x-www-form-urlencoded" ; Request = New HTTPRequest("/api/order_items/93076?order_item=30", Headers); Query.SetBodyFromString("", TextEncoding.UTF8, UseByteOrderMark.Don't Use); Connection.Write(Requête);

Et il est déjà tout à fait correct, probablement, de transférer les valeurs des paramètres elles-mêmes dans le corps de la requête.

La conclusion est la suivante : la plateforme 1C considère qu'une requête PUT sans corps est erronée et remplace la méthode par HEAD.

Il est curieux que 1C ne suive pas une requête POST sans corps et ne la transforme pas en GET, elle a été vérifiée par souci d'intérêt sportif.

Comme le dirait le célèbre Vovochka de la célèbre blague: "Où est la logique?".

J'espère que ma publication sauvera quelqu'un quelques heures de vie à la recherche d'une réponse. =)))

À partir de la deuxième version de la plate-forme 8, les utilisateurs et les développeurs ont la possibilité d'utiliser directement la requête http 1C. Le programme prend en charge deux types de requêtes :

  • requêtes POST ;
  • Requêtes GET.

Ainsi, un outil assez pratique a été créé pour échanger des données et interagir avec des services Web et des services fonctionnant via http.

OBTENIR la requête

Bien sûr, les exemples les plus simples d'utilisation de requêtes illustrent bien mieux leurs capacités que de nombreuses lignes de description. Alors essayons :

  1. Obtenir le corps de la page principale de notre site ;
  2. Élaborons la redirection de la requête ;
  3. Nous prendrons la photo du site.

Obtenir le corps du site

Commençons simple. Sur la Fig..

Le résultat de l'exécution de cette section de code est un texte assez volumineux, dont la dernière section est illustrée à la Fig.2.

Fig.2

Dans la première ligne de code, nous créons un objet de connexion avec une ressource http. Un objet peut contenir les propriétés suivantes :

  • Serveur - chaîne de connexion contenant l'adresse du serveur ;
  • Port - contient un numéro indiquant le port du serveur, par défaut, selon le type de connexion, vous pouvez spécifier 80 pour connexions non sécurisées ou 443 pour SSL sécurisé.
  • Nom d'utilisateur - spécifié si une autorisation sur le serveur est requise ;
  • Mot de passe – mot de passe de l'utilisateur sur la ressource spécifiée ;
  • Proxy - peut contenir un objet de type InternetProxy, indiqué lorsqu'un proxy est utilisé pour communiquer avec le serveur ;
  • SecureConnection - par défaut sur FALSE, le basculement sur TRUE indique l'utilisation du protocole https.

De plus, l'objet HTTPConnection possède ses propres méthodes, dont l'accès vous permet de décrire plus en détail l'algorithme d'exécution du gestionnaire :

  • CallHTTPmethod – contient deux paramètres obligatoires HTTPmethod et HTTPrequest, prend en charge la possibilité d'écrire le corps de la réponse dans le fichier spécifié dans le troisième paramètre ;
  • Write - envoie des données au serveur à l'aide d'une requête PUT ;
  • Modifier – modifie un objet en traitant les requêtes PATCH ;
  • SendForProcessing - une méthode indiquant l'utilisation d'une requête POST, comme dans toutes les méthodes précédentes, doit contenir le texte de la requête, elle peut également envoyer l'adresse du fichier de réponse pour l'écriture des données ;
  • Obtenez - plus d'informations à ce sujet seront discutées ci-dessous;
  • GetHeaders est une autre méthode qui sera utilisée tout au long de l'article ;
  • Delete est en fait une requête Delite qui supprime la ressource transmise dans la requête du serveur.

Dans la deuxième ligne, nous créons une requête vers le site sélectionné, le texte de notre requête contient une barre oblique, ce qui signifie que nous voulons obtenir page d'accueil. Si une expression suivait la barre oblique, par exemple "page2" ou "news", nous obtiendrions une autre page.

La troisième ligne exécute notre requête au serveur.

Dans le quatrième, nous montrons le résultat.

Gérer une redirection de requête http

Imaginez une situation où nous devons obtenir par programme un résultat de recherche via n'importe quel moteur de recherche par la touche "Requêtes en 1s". La section de code requise pour accéder à GOOGLE est illustrée à la Fig. 3

Fig.3

Ici, en plus des constructions qui nous sont déjà familières, il y a des Headers et un StatusCode. Traitons avec eux.

StatusCode - la valeur standard spécifiée dans "Request for Comments" , peut prendre les valeurs suivantes :

  1. Si tout va bien, une valeur comprise entre 100 et 299 sera renvoyée ;
  2. Dans le cas d'une redirection, un code compris entre 300 et 399 sera renvoyé, dans notre cas, une redirection permanente réussie vers la ressource sera déterminée par le code 301 ;
  3. En cas d'erreurs dans la requête, le paramètre prendra une valeur de 400 à 499 ;
  4. Une valeur comprise entre 500 et 599 indique des problèmes avec le serveur.

Chaque page comporte un en-tête, dans le texte duquel plusieurs paramètres peuvent être distingués (Fig. 4) :

  1. Schéma de câblage (tout jusqu'à deux barres obliques "//");
  2. barre d'adresse Connexions;
  3. Nom d'utilisateur et mot de passe;
  4. Port et hôte auxquels se connecter.

C'est cette décomposition qui est effectuée par la fonction BreakAddressString. Ayant ainsi obtenu une nouvelle adresse, nous pouvons enregistrer la page sur notre ordinateur et l'ouvrir dans le navigateur par défaut (procédure GetPage).

Fig.5

Il n'y a pas de nouvelles fonctionnalités et façons de travailler avec les requêtes, nous créons en fait Document texte depuis le corps du site et lancer la page dans le navigateur.

Nous plaçons le fichier à la racine du lecteur D et l'appelons test.

Obtenir une image du site

Une question naturelle se pose : si nous n'avons pas besoin du site entier, mais seulement de ses éléments individuels, est-il possible de le faire et comment ? Oui, vous pouvez. Le code de programme qui vous permet de le faire est illustré à la Fig. 6

Fig.6

Comme vous pouvez le voir sur la figure, dans le corps de la requête, nous avons le code de l'élément de structure du site que nous devons obtenir. Cette partie n'était pas dans notre description précédente et nous devons nous attarder sur ce point plus en détail.

Nous avons utilisé le navigateur Opéra pour accéder au site. Il a un outil important pour nous, lorsque vous faites un clic droit sur un élément, vous pouvez appeler menu contextuel, dont l'un des éléments est "Afficher le code de l'élément".

C'est grâce à lui que l'on peut obtenir l'adresse qui sera utilisée dans la requête Fig.7.

Demande POST

Contrairement aux requêtes Get simples, POST requêtes http avoir un corps de texte qui peut être stocké à la fois sous forme de texte brut et sous forme de fichiers avec des extensions xml, soap, json. Le réseau dispose de nombreux outils pour créer des textes de requête qui vous permettent de déboguer et de surveiller l'exécution de certaines requêtes.

En 1C, afin de lancer une requête avec un texte spécifique, l'objet requête HTTP dispose d'une procédure SetBodyFromString.

Dans la plate-forme 1C Enterprise 8.3, il est devenu possible de créer des services HTTP

Avec l'aide du langage intégré, il est maintenant possible de former une réponse à la demande. Dans ce cas, vous avez un accès pratique au corps, aux en-têtes et à la ligne de la source demande, et il est également possible de générer du code, du corps et des en-têtes réponseà votre discrétion.

Par rapport aux services Web disponibles dans la plate-forme SOAP, les services HTTP présentent un certain nombre d'avantages :

  • Facilité de programmation du client de tels services ;
  • Potentiellement plus petite quantité de données transférées ;
  • Charge de calcul potentiellement moindre ;
  • Les services HTTP sont orientés "ressources", tandis que les services SOAP sont orientés "action".

La base de données montre la mise en œuvre des services http

Liste des factures du service http

Les modèles d'URL sont utilisés dans le service http, la gestion des propriétés est implémentée ParamètresURL objet HTTPServiceRequest
À cet exemple montre comment créer un soubassement entre la base de travail et le site de l'entreprise
La connexion est faite à la base de démonstration " Gestion commerciale 11", dans lequel vous devez d'abord définir une propriété supplémentaire avec le nom Mot de passe Internet , où nous stockerons le mot de passe pour l'accès.
La requête http sera passée en paramètres d'URL : TIN comme identifiant et mot de passe.
Lors du traitement de la demande, une connexion est établie via ComConnector à l'UT (les freins sont garantis), et à partir de là, une sélection est effectuée
Je ne revendique pas la rapidité et la sécurité de cette solution, c'est un exemple

Alors. Une nouvelle branche est apparue dans l'arborescence des métadonnées - Services HTTP
Nous créons nouveau service, indiquez son nom et son URL racine (liste)
L'url racine sera utilisée pour appeler notre service http
Ensuite, ajoutez un modèle d'URL au service http, en spécifiant "/(Connexion)/(Mot de passe)" comme modèle
Un tel modèle permettra, lors du traitement d'une requête http, d'obtenir la structure de paramètres correspondante et leurs valeurs dans les paramètres d'URL
Maintenant, ajoutons une méthode appelée "get" à notre modèle d'URL et sélectionnons GET comme méthode http.
Ouvrez le gestionnaire et écrivez le code
Un gestionnaire de méthode est une fonction qui doit renvoyer une valeur de type HTTPServiceReponseHTTPServiceResponse

Service HTTPOrderStatus

L'exemple met en oeuvre le traitement des variables passées par la méthode POST, la formation d'une réponse sous la forme d'une page html.
Cette fois, les données sont extraites de la base de données où se trouve hs, donc cela fonctionne beaucoup plus rapidement que le service http précédent.
Lors de la mise en œuvre système de travail il est logique de créer des objets dans la base de données (avec le service) et de configurer la migration des données à partir de la base de données source (par exemple, un processus d'arrière-plan). Lors du traitement d'une requête http, effectuez une sélection directement depuis la base de données où elle se trouve.

Publication

Il existe de nombreuses informations sur l'installation et la configuration d'un serveur Web.
J'ai utilisé la construction httpd-2.2.25-win32-x86-openssl-0.9.8y.exe d'ici
Installé en utilisant la méthode "Next-Next-Finish" 🙂
La publication de services http se situe au même endroit où se trouvait et se trouve la publication de services Web, et n'est pas particulièrement différente.
Après avoir installé le serveur web en mode "Configurateur", allez dans le menu "Administration" - "Publier sur un serveur web"
Dans l'onglet "Services HTTP", définissez le nom de publication, le serveur Web, le répertoire de publication et marquez nos services (dans mon cas, le nom est "web", serveur Web Apache 2.2)
Lors de la publication, les blocs correspondants sont automatiquement écrits dans le fichier de configuration httpd.conf et le serveur est redémarré (à la première publication)
Appeler un service http
Exemple: http://monsite/web/hs/list, où
mon site– adresse du serveur (si le serveur Web est installé localement, vous pouvez utiliser 127.0.0.1)
la toile- le nom spécifié au moment de la publication (alias)
hs- un segment de chemin obligatoire qui indique au serveur qu'il fonctionnera avec les services http
liste– URL racine du service Web

Essai

Liste des factures

http://127.0.0.1/web/hs/list/7705260681/pswMP (N'oubliez pas de configurer une propriété supplémentaire dans l'UT pour le mot de passe)

Il est supposé que pour accéder au registre des documents, l'utilisateur utilise un lien direct contenant le NIF et le mot de passe

Statut de la commande

http://127.0.0.1/web/hs/check

La requête et la réponse se trouvent sur la même URL. En entrant dans la page, la méthode GET est déclenchée, renvoyant le formulaire html

Lorsque vous cliquez sur "Vérifier", le numéro de commande est envoyé par la méthode POST à ​​la même URL, la réponse est renvoyée avec le même formulaire de demande, complété par des données sur la commande demandée.

Dans le fichier joint - déchargement de la base de données pour 1C 8.3. La configuration implémente 2 services http (à partir de la publication), établissant une com-connexion avec la base de démonstration UT 11, le document "Commande".

Ce dont vous avez besoin pour commencer et tester

  • serveur Web
  • n'importe quel navigateur Web
  • version actuelle1C : Entreprise 8.3

Eh bien, voici un exemple de traitement d'un fichier XML avec des contreparties côté serveur :

Code VBS
require_once dirname(__FILE__) . "/../inc/initf.php" ;
classe Onec_Import_Customers(
$instance statique privée ;
fonction __construct() ()(

Soi ::$instance = $this ;

processus de fonction publique ()()
$rawHttp = file_get_contents("php://input") ;
$xml_raw = str_replace("xml=", "", $rawHttp) ;

Si ($_SESSION["connecté"] || vrai)(
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", "REQUEST " . print_r($_REQUEST, 1) . " SERVER " . print_r($_SERVER,1). " FILES " . print_r($_FILES,1) . $xml_raw) ;

//$xml = stripslashes($_POST["xml"]);
$xml = stripslashes($xml_raw);
si(!$xml) (
$xml = $xml_raw ;
//die("pas de données XML (post key "xml")") ;
}
si ($this->setCustomers($xml)) (
mourir("OK");
) autre (
mourir("ECHEC") ;
}
) autre (
mourir();
}
}

Fonction privée setCustomers($xml)(
$db = db::getInstance() ;

$sxml = simplexml_load_string($xml) ;

$clients = $sxml->("P”PsPiPsPIRsSâ”) ? $sxml->("R”PsPiRsPIRsSЂ") : self::err("Format de fichier invalide. Clients.") ;

$final = tableau();
$k = 0 ;

$touslesclients = tableau();

Foreach ($clients comme $cust) (
$password = base::generatePassword(6,1) ;

$arr["mot de passe"] = $motdepasse ;

$arr ["email"] = (array)$cust->("Почта") ;//? (array)$cust->("PџPѕS‡S‚P°") : self::err("Format de fichier invalide. N° client :" . $k . ". Email invalide") ;
$arr["email"] = $arr["email"] ? $arr ["email"] : "";//: self::err("Format de fichier invalide. numéro de client :" . $k . ". Email invalide") ;

$arr ["app_name"] = (array)$cust->("НаименоваРРЅРёРµ") ;//? ;
$arr ["app_name"] = $arr ["app_name"] ? $arr ["app_name"] : "";//self::err("Format de fichier non valide. numéro de client :" . $k . ". Nom non valide") ;

$arr ["clientid"] = (array)$cust->("Номер") ? (array)$cust->("Номер") : self::err("Format de fichier invalide. N° clients :" . $k . ". ID client invalide") ;
$arr["clientid"] = $arr["clientid"] ? $arr ["clientid"] : self::err("Format de fichier invalide. Clients no :" . $k . ". Clientid invalide") ;

$arr ["date"] = (tableau)$cust->("R”R°C‚R°") ? (array)$cust->("P”P°S‚P°") : self::err("Format de fichier invalide. N° de client :" . $k. ". Date invalide") ;
$arr["date"] = $arr["date"] ? $arr ["date"] : self::err("Format de fichier invalide. N° de client :" . $k . ". Date invalide") ;

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

$arr ["phone_home"] = (array)$cust->("Телефон") ;//? (array)$cust->("PўPµP"PµS„PsPS") : self::err("Format de fichier invalide. N° de client :" . $k . ". Téléphone invalide") ;
$arr ["phone_home"] = $arr ["phone_home"] ? $arr ["phone_home"] : "";//self::err("Format de fichier non valide. Numéro de client :" . $k . ". Téléphone non valide") ;

$arr ["quartier"] = (tableau)$client->("P P°P#PsPS") ;//? (array)$cust->("P P°P#PsPS") : self::err("Format de fichier invalide. N° de client :" . $k . ". District invalide") ;
$arr ["quartier"] = $arr ["quartier"] ? $arr ["district"] : "";//self::err("Format de fichier invalide. Numéro de client :" . $k . ". District invalide" );

$arr ["rue"] = (tableau)$client->("PJP"PeC†P°") ;//? (array)$cust->("PJP"PoC†P°") : self::err("Format de fichier invalide. N° de client :" . $k . ". Rue invalide") ;
$arr["rue"] = $arr["rue"] ? $arr ["rue"] : "";//self::err("Format de fichier invalide. N° de client :" . $k . ". Rue invalide") ;

$arr ["building"] = (array)$cust->("R”RѕRј") ;//? (array)$cust->("P”PѕРј") : self::err("Format de fichier invalide. N° de client :" . $k . ". Bâtiment invalide") ;
$arr["bâtiment"] = $arr["bâtiment"] ? $arr ["bâtiment"] : "" ;//self::err("Format de fichier invalide. N° de client :" . $k . ". Bâtiment invalide") ;

$arr ["appartement"] = (array)$cust->("PљPIR°СЂС‚РёСЂР°") ;//? (array)$cust->("Квартира") : self::err("Format de fichier invalide. No client :" . $k . ". Appartement invalide") ;
$arr ["appartement"] = $arr ["appartement"] ? $arr ["appartement"] : "";// self::err("Format de fichier invalide. N° de client :" . $k . ". Appartement invalide") ;

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

$final = $arr ;
++$k ;
}

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

Fonction statique privée sendPasswordToMail($email, $client_id, $password) (
$db = db::getInstance() ;
$config = config_model::getInstance() ;
$lng = Request::$currentLang["id"] ;
$email_text = $db->getRow("s1_text", "*", "`alias`="registration_ok" AND `lng_id`="($lng)"") ;
$body = str_replace("%password%", $password, $email_text["content"]) ;
$body = str_replace("%client_id%", $client_id, $body) ;
base::mailSend($body, $email_text["title"] . " - " . $config->defaultTitle("site.ru") , $email, $app["app_name"], $config->site_admin_mail( " [courriel protégé]"), $config->from_name("site")) ;

Fonction privée buildCustomers($data)(

$db = db::getInstance() ;

$qry = "I_nsert INTO s1_customer (`active`,`password`,`app_name`,`email`,`date`,`clientid`,`phone_home`,`street`, `district`, `building`, `apartament `) VALEURS " ;
foreach ($données en $lignes)(
$queryArr = "(
"0"
,MD5("($lignes["mot de passe">")
,"($db->escape($rows["app_name"]))"
,"($db->escape($rows["email"]))"
,"($db->échappement($lignes["date"]))"
,"($db->escape($rows["clientid"]))"
,"($db->escape($rows["phone_home"]))"
,"($db->escape($rows["street"]))"
,"($db->escape($rows["district"]))"
,"($db->escape($rows["building"]))"
,"($db->escape($rows["appartement"]))"
)" ;
}
$qry .= implode(",", $queryArr) ;
$qry .= " SUR LA MISE À JOUR DE LA CLÉ EN DOUBLE
`app_name` = VALEURS(app_name)
,`date` = VALEURS(date)
,`email` = VALEURS(email)
,`phone_home` = VALEURS(phone_home)
,`rue` = VALEURS(rue)
,`district` = VALEURS(district)
,`bâtiment` = VALEURS(bâtiment)
,`appartement` = VALEURS(appartement)
" ;
retourne $db->query($qry) ;
}

fonction statique publique getInstance() ()
si (!self::$instance)
{
nouveaumoi() ;
}
return self::$instance ;

Fonction statique privée err($msg) (
lance une nouvelle exception ImportException($msg) ;
}

La classe ImportException étend Exception(

Fonction __construct($msg)(
die ("Erreur : " . $msg) ;