HTTP-сервисы появились в платформе 8.3.5 и с тех пор начали активно развиваться. С их помощью можно реализовать обмен данными без использования COM. Или создать какой-нибудь frontend для информационной базы.
В данной статье я опишу frontend, использующий JQuery и AJAX запросы. Все объекты можно создавать как непосредственно в самой конфигурации, так и в расширении.
Итак, приступим. Вначале создадим объект конфигурации HTTP-сервис, укажем корневой URL, например, front
В нем создадим 5 шаблонов URL и методы к ним:
- Старт — для инициализации начальной страницы; шаблон /index; HTTP-метод GET
Свойства метода "Получить" шаблона "Старт"
- JS — для получения JavaScript’ов для страницы; шаблон /js; HTTP-метод GET
- CSS — для стилей для страницы; шаблон /css; HTTP-метод GET
- JQuery — для подключения библиотеки JQuery; шаблон /jquery; HTTP-метод GET
- ajax — для вызова; шаблон /ajax; HTTP-метод POST
Свойства метода "МетодAJAX" шаблона "ajax"
Тексты скриптов JS, описание стилей CSS, библиотеку JQuery (Скачать) и начальную страницу HTML поместим в макеты обработки HTTP_ОбработкаСервиса. Процедуры для обработки запросов поместим в менеджер этой обработки.
Добавим экспортную функцию ПолучитьНачальнуюСтраницу() в модуль менеджера для загрузки начальной страницы
Функция ПолучитьНачальнуюСтраницу() Экспорт
возврат ПолучитьМакет("НачальнаяСтраница").ПолучитьТекст();
КонецФункции
Функция ОбработатьЗапросAjax(СтруктураJSON) Экспорт
Контент="Вы ввели <b>"+
СтруктураJSON.t+
"</b>";
возврат Контент;
КонецФункции
Заполним макеты:
Макет НачальнаяСтраница может иметь тип ТекстовыйТекумент, а может, как в данном случае, и HTTMДокумент.
(в тексте для публикации пришлось заменить onclick= на _onclick_=, иначе редактор просто удалял этот фрагмент. При копировании кода нужно убрать выделение знаками "_")
Макет "НачальнаяСтраница"
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;">
<script type="text/javascript" src="./jquery"></script>
<script type="text/javascript" src="./js"></script>
<link rel="stylesheet" href="./css" type="text/css">
</head>
<body>
<p>Проверка</p>
Введите имя<input type="text" id="e_name">
<button type="submit"
id="okButton"
style="top: 8px; left: 0px; height: 21px; width: 80px;"
_onclick_="GetContent(this)">
OK
</button>
<div id="content">
Контент
</div>
</body>
</html>
В макет JS включим скрипты для обработки логики нашего front‘a
var cur_url=""; //Переменная для хранения корневого адреса страницы
//--------Инициализация
$(document).ready(function(){
cur_url=document.location.href.substring(0, document.location.href.lastIndexOf("/"));
})
//--------------Функции--------------------
function GetContent(th)
{
$.ajax({
type: "POST",
url: cur_url+"/ajax",
data: JSON.stringify({action: "test", t: $("#e_name").val()}),
cache: false,
success: function(html){
$("#content").html(html);
}
});
}
Теперь перейдем в модуль HTTP-Сервиса и создадим обработчики методов Получить, ПолучитьJS, ПолучитьСSS, ПолучитьJQuery и МетодAJAX:
Функция СтартПолучить(Запрос)
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки(Обработки.HTTP_ОбработкаСервиса.ПолучитьНачальнуюСтраницу());
Возврат Ответ;
КонецФункции
Функция JSПолучитьJS(Запрос)
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки(Обработки.HTTP_ОбработкаСервиса.ПолучитьМакет("JS").ПолучитьТекст());
Возврат Ответ;
КонецФункции
Функция CSSПолучитьСSS(Запрос)
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки(Обработки.HTTP_ОбработкаСервиса.ПолучитьМакет("CSS").ПолучитьТекст());
Возврат Ответ;
КонецФункции
Функция JQueryПолучитьJQuery(Запрос)
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки(Обработки.HTTP_ОбработкаСервиса.ПолучитьМакет("JQuery").ПолучитьТекст());
Возврат Ответ;
КонецФункции
Функция ajaxМетодAJAX(Запрос)
ТелоЗапроса = Запрос.ПолучитьТелоКакСтроку();
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ТелоЗапроса);
СтруктураJSON = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки(Обработки.HTTP_ОбработкаСервиса.ОбработатьЗапросAjax(СтруктураJSON));
Возврат Ответ;
КонецФункции
Сохраняем конфигурацию (расширение).
Теперь необходимо опубликовать наш HTTP-сервис
Пример файла публикации default.vrd
<?xml version="1.0" encoding="UTF-8"?>
<point xmlns="http://v8.1c.ru/8.2/virtual-resource-system"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
base="/demo"
ib="File="C:UsersAdminDocumentsБазыDemo";Usr=web;Pwd=123;"
enable="false"
allowexecutescheduledjobs="">
<httpServices publishExtensionsByDefault="true">
<service name="HTTP_Front"
rootUrl="front"
enable="true"
reuseSessions="autouse"
sessionMaxAge="200"
poolSize="10"
poolTimeout="50"/>
</httpServices>
<standardOdata enable="false"
reuseSessions="autouse"
sessionMaxAge="20"
poolSize="10"
poolTimeout="5"/>
</point>
Перезапускаем веб сервер и набираем в адресной строке http://127.0.0.1/demo/hs/front/index. Произойдут следующие действия:
- 1С выполнит СтартПолучить и вернет текст начальной страницы
- Браузер при загрузке страницы обнаружит, что нужно загрузить еще три ссылки http://127.0.0.1/demo/hs/front/jquery, http://127.0.0.1/demo/hs/front/js и http://127.0.0.1/demo/hs/front/css и передаст вызовы 1С через веб сервер
- 1С выполнит методы JQueryПолучитьJQuery, JSПолучитьJS, CSSПолучитьСSS и вернет содержание браузеру.
- Страница полностью загрузится
Теперь на полученной веб-странице введем значение в поле и нажмем кнопку Ок. Начнется выполнение ajax-запроса и 1С вернет какой-нибудь контент, который включиться в содержимое блока <div id="content"> без полной перезагрузки страницы.
Хочу отметить, что во время разработки и отладки после каждого сохранения, необходимо перезапускать веб-сервер, чтобы он перечитал конфигурацию. Упростить это можно, заменив на время вызов внешней обработки из модуля HTTP-Сервиса, правда придется использовать не модуль менеджера, а модуль объекта. Но это мелочи.
Бонусом опубликую php-скрипт, который кэширует запросы, тем самым минимизирует обращения напрямую к информационной базе
<?php
$url="http://127.0.0.1/demo/hs/front/index";
$cache_path="/var/www/html/cache";
$history = 2;
//ini_set('display_errors',1);
//error_reporting(E_ALL);
$path = substr($url, 0, strrpos( $url, '/'));
if (count($_POST)==0){
//$html = file_get_contents($url);
$html=get_extfile('./index', $path, $cache_path);
$url_js=array();
$dom = new DOMDocument;
$dom->loadHTML($html);
$scripts = $dom->getElementsByTagName('script');
foreach ($scripts as $script) {
$name_s = $script->getAttribute('src');
$text_s = get_extfile($name_s,$path,$cache_path);
if($name_s=='./js.js') $text_s = str_replace('/ajax','/index.php',$text_s);
$s= $dom->createTextNode($text_s);
$script->removeAttribute('src');
$script->appendChild($s);
}
$links = $dom->getElementsByTagName('link');
$head= $dom->getElementsByTagName('head');
foreach ($links as $l)
if ($l->getAttribute('type')=='text/css')
{
$name_s = $l->getAttribute('href');
$text_s = get_extfile($name_s,$path,$cache_path);
$s = $dom->createTextNode($text_s);
$style=$dom->createElement('style');
$style->appendChild($s);
$head->item(0)->appendChild($style);
$l->setAttribute('href','');
}
$html = $dom->saveHTML();
//echo($url_js);
echo($html);
die();
}
$query=file_get_contents('php://input');
$query_file=$cache_path."/".hash('md5',$query);
$rasd='$%@#';
$new_cache=false;
$now = time();
$use_cache = (strripos($query,'nocache') === false) ? true : false ;
if ($use_cache){
if (!file_exists($query_file)) $new_cache=true;
else
if ($now - filemtime($query_file) >= 60 * 60 * $history ) $new_cache=true;
} else $new_cache=true;
if (!$new_cache)
{
$fp = fopen($query_file, "r");
$contents = fread($fp, filesize($query_file));
fclose($fp);
$data=explode($rasd,$contents);
//$data=preg_split($contents,$rasd);
if ($data[0]==$query)
{
$response=$data[1];
}
else $new_cache=true;
}
if ($new_cache)
{
$ch = curl_init($path . '/ajax');
// устанавлваем даные для отправки
curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
// флаг о том, что нужно получить результат
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// отправляем запрос
$response = curl_exec($ch);
// закрываем соединение
curl_close($ch);
if ($use_cache)
{
$fp = fopen($query_file, "w");
// записываем в файл текст
fwrite($fp,$query.$rasd.$response);
// закрываем
fclose($fp);
}
}
echo($response);
function get_extfile($name, $path, $cache_path)
{
$ext_file = $path . str_replace('./','/',$name);
$cache_file=$cache_path ."/". str_replace('./','/',$name);
$new_cache=false;
$now = time();
$history = 2;
if (!file_exists($cache_file)) $new_cache=true;
else
if ($now - filemtime($cache_file) >= 60 * 60 * $history ) $new_cache=true;
if (!$new_cache)
{
$fp = fopen($cache_file, "r");
$text = fread($fp, filesize($cache_file));
fclose($fp);
return $text;
}
$text=file_get_contents($ext_file);
$fp = fopen($cache_file, "w");
// записываем в файл текст
fwrite($fp,$text);
// закрываем
fclose($fp);
return $text;
}
?>
Спасибо большое, отличная статья.
Предложение: в макете «Начальная страница» вставить ссылку на загрузку JQuery с Google, а не с сервера IIS (если речь идет не о пользователях в локальной сети)
Непонятно, почему часть кода по получению макетов в модуле http-сервиса, а часть в модуле менеджера обработки.
В модуле http-сервиса примерно такой код, для каждого url своя строка с названием макета:
Показать
В модуле менеджера обработки:
Правильно ли я понял, что для каждой страницы нужно будет повторять схему, или заморачиваться с параметрами?
(2) Статья описывает один из вариантов реализации. А вариантов может быт куча.
(3) Это зависит от разработчика. Я обычно содержание одной страницы изменяю js-скриптом в зависимости от параметров ajax-запроса. В этой публикации этот метод и реализован.
Я правильно понимаю, что Вы храните javascript и css файлы (/JS и /CSS) как макеты в 1С? Если да, то с какой целью?
(6) Да храню. С той же целью, что и, например, хранятся правила обмена между зарплатой и бухгалтерией .
(7)Честно говоря не уловил связи между правилами обмена и файлами стилей :). У Вас же все равно я так понимаю на фронте php?
(8) Нет. php — это так, примочка для кеширования, работает как «шлюз». Все прекрасно работает и без нее. js и css нужно же где-то хранить и не потерять при переносе/развертывании конфигурации. Как вариант — их можно хранить и в теле страницы html, и внешних файлах.
(9)
Ну я собственно к этому и клоню.
В Вашем случае при хранении в 1С Вы создаете дополнительную бесполезную нагрузку на сервер приложений.
К тому же, как скажем верстальщик будет дорабатывать ваш фронт в обработке?
(10) я не предлагаю создавать полноценное веб-приложение на 1С на большое число соединений. Тут и лицензий не напасешся. Я просто описал один из вариантов реализации простого «фронта». И кстати, браузеры сами кэшируют js и css, указанные в <head>
(10)
Все идет к тому, чтобы использовать некий обработчик шаблонов по типу как twig для php.
(12)Полностью согласен, это хорошая идея. Что-то типа:
https://infostart.ru/public/549791/
(11)
Ну тогда для чего это может быть на Ваш взгляд использовано?
Как пример того, что http-сервис может возвращать html и другую текстовую (и не только) информацию (js & css) — подойдет.
Как подход для создания чего-либо более сложного, чем hello world — не уверен, т.к. гораздо удобнее создавать и редактировать html, css и js каким-либо заточенным для этого редактором, а не ковыряться в макете. И это не зависит от количества соединений и лицензий, просто на мой взгляд предложенный подход неудобен.
Давно хочу написать статью про фронт на VueJS но пока найду время, кто нибудь уже напишет (
Правильное решение — статическое содержимое ранить в файлах. А запросами к http сервису получать динамическое содержимое.
Все остальные универсальные решения хороши только как пример для начинающих или «еще одна статья».
(14) Здесь и не написано, что разрабатывать и отлаживать нужно в макете. Я, например, сначала все подготавливал отдельными фалами и редактором notepad++, а потом помещал все в макеты.
(17)Вот и получается, что Вам надо иметь файловую копию для отладки и разработки, которую Вы руками пофайлово синхронизировать со своими макетами. Вопрос в том зачем, если можно этого не делать.
(11) Никаких проблем с лицензиями нет. HTTP сервисы не используют лицензии.
(19) Физически нет. Юридически да.
https://v8.1c.ru/predpriyatie/questions_licence.htm#59
(18) если большое и сложное веб-приложение с постоянной модернизацией, то согласен. А если что-то вроде ежедневного отчета для сотрудников или вывода какой-либо статистики на большой монитор, то зачем. Или если конфигурация тиражируется в филиалы, или РИБ
(20) Там используется такое понятие как «одновременно осуществляется доступ».