HTTP Сервисы: Путь к своему сервису. Часть 1










Уже много было написано про http-сервисы, но то и дело всплывают «Новые» статьи по обмену между базами V8 по COM, что «Немножко» удивляет. Решил внести свои 5 копеек, поработаем с http-сервисом.

Я уже писал статью с использованием HTTP-сервисов (Мобильный клиент + HTTP Сервис + Расширение конфигурации), но там было все сумбурно без объяснений, почему именно так. В данном цикле статей расскажу и покажу в примерах накопленный опыт в данном вопросе, и мы сделаем простой легко разворачиваемый каркас HTTP-сервиса.

Примеры будут сделаны в расширении конфигурации, на платформе 8.3.10.2650. Для опытов установил ERP 2.4.3.145(Но вообще непринципиально, ставим любую свежую конфигурацию под 8.3.10). Так как параллельно в свободное время веду разработку универсального решения под названием Pretty API или «PAPI», расширение будет содержать данную аббревиатуру.

Начнем.

Почему http-сервис?

А) HTTP сервисы на платформе 1С 8.3.5.1068 появились летом 2014 года, то есть 4 года назад, а Web-сервисы и того больше. Это кощунство не использовать их до сих пор.

Б) На Хабре в официальном блоге Фирмы 1С есть статья Способы интеграции с 1С от 25 августа 2024, почитайте ее, особенно в части устаревших технологий.

В) Геморрои с разными версиями и «comcntr.dll» забываем как страшный сон! Опубликовали и пользуемся, плюсом мы получаем Вэб клиент, мобильный клиент, легкое использование нашего сервиса другими программистами (собственно API) и другие пряники.

Г) Скорость! Использую Com последние 3 года только для того чтобы показать сравнение со стандартным интерфейсом oData или http-сервисом. Когда люди видят вживую, они даже иной раз не верят, что обмен прошел!

Это все равно, что ездить каждый год на поезде по 3 суток в сторону Сочи и вдруг слетать на самолете за 2,5 часа.

!!! Использование технологии COM (доступно только на платформе Windows) !!!

Д) С версии 8.3.7.1759 могут быть встроены через расширение, а с версии 8.3.9 плюсом к ним можно встроить модули для более простой работы с ними.

E) Простота и гибкость разработки.

Ж) Стагнация — это плохо! В работе можешь не использовать, но быть всегда готов. Нельзя стоять на месте, если пошел в IT сферу.

Еще много чего можно перечислить. Минусы, тоже есть, но плюсов в разы больше.

Самый главный минус. Нужно установить и настроить веб сервер (IISApache, 1С: Публикатор или 1С: Линк – Apache с интерфейсом для простого пользователя). Тут вот в чем проблема: Чаще всего администраторы почему-то не в состоянии это сделать, и приходится настраивать самому, либо они тупо устанавливают по дефолту и там начинаются пляски с бубном. Благо сейчас статей по настройки пруд пруди, ниже приведу парочку загугленных:

Пошаговая инструкция настройки web-сервисов для 1Сv8.3 и IIS 8.5, в данной инструкции особенно выделю пункт 8.

Настройка веб сервера Apache + 1С (Пошаговое руководство)

Лично я использую IIS, но на вкус и цвет как говорится.

Ближе к делу.

Создадим демо конфигурацию для опытов и добавим в него расширение. Можно создавать все объекты и не в расширении, я просто показываю вариант без изменения конфигурации. (В расширении добавление HTTP-сервисов появилось с версии 8.3.7.1759.)

Давайте перед созданием нашего HTTP-сервиса разберемся из чего складывается URL (подробнее описано на ИТС в главе 17.2.2. HTTP-сервисы):

http://host/base/hs/корневойURL/относительныйURL?ПараметрыЗапроса

host IP адрес или доменное имя веб сервера.

base – Имя базы. Указывается при публикации.

hs — признак того, что выполняется обращение к HTTP-сервису.

корневойURL — имя ресурса, которое определяет группу ресурсов, связанных общим смыслом.

относительныйURL — определяет ресурс, к которому будет выполняться обращение. Относительный URL, указанный в запросе, будет использован для определения конкретного ресурса, к которому выполнялось обращение. Правило сопоставления задается в объекте Шаблон URL.

ПраметрыЗапроса Не всегда обязательные параметры передаются после знака «?», чаще всего дополнительные параметры или параметры выборки, например формат ответа(format=json или format=atom).

Теперь по порядку:

Создаем сервис и задаем ему корневойURL:

Создаем Шаблон URL:

При создании шаблона можно использовать следующие символы:

Любые символы, допустимые в идентификаторах языка «1С:Предприятие».

Символ «/»;

Символы «{}» с непустым текстом между ними;

Символ *.

Наш шаблон выглядит следующим образом: /V1/{ИмяМетода}

Где {ИмяМетода} является параметром. Параметр может состоять из букв, цифр и символа подчеркивания «_».

Почему такой шаблон?

Когда смотришь различные примеры, коих очень много в шаблоны запихивают параметры. Создают по несколько методов с разными параметрами. А зачем так делать?

Вот пример с ИТС (17.2.2.3.2. Работа с документами):

Видно, что создано два Шаблона с методом Get, но по большому счету отличаются они только тем, что один ищет по номеру документ, а второй выводит все.

Все это можно реализовать одним методом, список или документ подавать в параметр ИмяМетода, а дополнительными параметрами передавать номер. А давайте сделаем!

Добавляем метод GET.

Берем код из примера ИТС.

 

 17.2.2.3.2. Работа с документами (Тестовый пример)

Функция СписокGET(Запрос)
Ответ = Новый HTTPСервисОтвет(200);
Результат = "Расходная накладная, 1, 01.01.2014
|Расходная накладная, 2, 01.01.2014";
Ответ.УстановитьТелоИзСтроки(Результат);
Возврат Ответ;
КонецФункции
Функция ДокументGET(Запрос)
Ответ = Новый HTTPСервисОтвет(200);
Номер = Число(Запрос.ПараметрыURL.Получить("number"));
Если Номер > 2 Тогда
Ответ.КодСостояния = 404;
Ответ.УстановитьТелоИзСтроки("Отсутствует документ с номером: " + Номер);
Иначе
Если Номер=1 Тогда
Ответ.УстановитьТелоИзСтроки("Расходная накладная, 1, 01.01.2014");
Иначе
Ответ.УстановитьТелоИзСтроки("Расходная накладная, 2, 01.01.2014");
КонецЕсли;
КонецЕсли;
Возврат Ответ;
КонецФункции

 

Видоизменяем его и добавляем код обработки метода:

 

 Функция PrettyAPIGET

Функция PrettyAPIGET(Запрос)
Ответ = Новый HTTPСервисОтвет(200);

ИмяМетода = Запрос.ПараметрыURL.Получить("ИмяМетода");

Если ИмяМетода = "Список" Тогда
Результат = "Расходная накладная, 1, 01.01.2014
|Расходная накладная, 2, 01.01.2014";

ИначеЕсли ИмяМетода = "Документ" Тогда
//ПраметрыЗапроса - number
ПарНомер = Запрос.ПараметрыЗапроса.Получить("number");
Номер = Число(?(ПарНомер=Неопределено,0,ПарНомер));
Если Номер > 2 Тогда
Ответ.КодСостояния = 404;
Результат = "Отсутствует документ с номером: " + Номер;
Иначе
Если Номер = 1 Тогда
Результат = "Расходная накладная, 1, 01.01.2014";
Иначе
Результат = "Расходная накладная, 2, 01.01.2014";
КонецЕсли;
КонецЕсли;
Иначе
Ответ.КодСостояния = 405;
Результат = "Отсутствует Метод " + ИмяМетода;
КонецЕсли;

Ответ.УстановитьТелоИзСтроки(Результат,КодировкаТекста.UTF8);
//Ответ.Заголовки.Вставить("Content-Type","text/html; charset=utf-8");
Возврат Ответ;
КонецФункции

 

Выполняем публикацию нашего сервиса:

Проверяем результат:

1 Получим список. Запрос: http://127.0.0.1/DemoEnterprise2_4_3_145/hs/PrettyAPI/V1/Список

Результат:

Получаем какие-то «кракозябры»! Первый раз я нарвался на этот момент с кодировкой около 4-х лет назад, ну и так как на ИТС пример как раз приводит к этому, решил показать и рассказать, как исправить.

Вы обратили внимание, что в коде функции PrettyAPIGET я оставил в самом конце закомментированную строку

//Ответ.Заголовки.Вставить("ContentType","text/html; charset=utf-8");

Разкомментируем ее и проверим, как теперь отработает наш сервис.

2 Получим документ с номером 1. Запрос: http://127.0.0.1/DemoEnterprise2_4_3_145/hs/PrettyAPI/V1/Документ?number=1

Результат:

Важно: Хотелось бы обратить внимание на коды состояния из примера выше. Мне раза три в моей практике попадались API, которые всегда возвращали ответ с кодом 200 (200 OK («хорошо»)) и только в теле ответа, можно было понять, была ли ошибка. Это грубейшая ошибка разработчиков! Ну или это неуважение к конечному потребителю…

Передавая ответ, не забывайте про коды состояния (Список кодов состояния)!

Вот тут хороший пример по работе с ответом в зависимости от кода состояния, обратите внимание на ошибку с кодами 3XX.

Как Вы видите, мы обошлись одним Шаблоном для той же задачи. По сути можно сделать некий универсальный каркас для HTTP-метода и решать любую задачу Интеграции.

Давайте разобьем все возможные сервисы на блоки, чтобы понять, как сделать некое универсальное решение.

Сервис выполняет следующие действия:

  1. Получение входящих параметров и проверка их корректности
  2. Выполнение основных действий
  3. Формирование ответа

Если посмотреть пример выше, то понимаем, что все идет в вперемешку, не структурированно. Отлаживать такой сервис не очень приятно!

Я предпочитаю для HTTP-методов создавать отдельные модули и «Выполнение основных действий» осуществлять в созданном модуле. Создание отдельного модуля позволяет отлаживать HTTP-сервис через внешнюю обработку, это бывает необходимо при получении ошибки, которая говорит, что в коде есть ошибка, но отладка по HTTP не останавливается на точке остановы. Давайте «причешем» пример выше.

Создадим модуль и переделаем «получение параметров» и «формирование ответа».

 

Функция PrettyAPIGET 

Функция PrettyAPIGET(Запрос)
СтруктураВхПараметров = Новый Структура;
//Получаем имя метода
перИмяМетода  = Запрос.ПараметрыURL["ИмяМетода"];
//Помещаем имя метода в структуру
СтруктураВхПараметров.Вставить("ИмяМетода",перИмяМетода);

//Забираем параметры из запроса
ВхПараметрыЗапроса = Новый Соответствие;
Для каждого Параметр Из Запрос.ПараметрыЗапроса Цикл
ВхПараметрыЗапроса.Вставить(Параметр.Ключ,Параметр.Значение);
КонецЦикла;
СтруктураВхПараметров.Вставить("ПараметрыЗапроса",ВхПараметрыЗапроса);

//Передаем входящие параметры (Модуль для метода GET)
СтруктураОтвет = PAPI_ОбработкаМетодовGET.PAPI_ОбработкаМетодовGET(СтруктураВхПараметров);

//Создаем ответ с кодом состояния
Ответ = Новый HTTPСервисОтвет(СтруктураОтвет.КодОтвета);
Если СтруктураОтвет.Отработало Тогда
Ответ.УстановитьТелоИзСтроки(СтруктураОтвет.ДанныеОтвета,КодировкаТекста.UTF8);
Иначе
Ответ.УстановитьТелоИзСтроки(СтруктураОтвет.ТекстОшибки,КодировкаТекста.UTF8);
КонецЕсли;

Ответ.Заголовки.Вставить("Content-Type","text/html; charset=utf-8");
Возврат Ответ;
КонецФункции

 

 

 Модуль PAPI_ОбработкаМетодовGET

//Функция экспортная, специально чтобы можно было отлаживать как по HTTP(https://its.1c.ru/db/metod8dev#content:5756:hdoc)
//Так и через внешнюю обработку
Функция PAPI_ОбработкаМетодовGET(СтруктураВхПараметров) Экспорт
//структура ответа. Собственна нужна для формирования ответа
СтруктураОтвет = Новый Структура("ДанныеОтвета,Отработало,ТекстОшибки,КодОтвета","",Истина,"",200);

//Переправляем на нужный метод
Если ВРег(СтруктураВхПараметров.ИмяМетода) = ВРег("Список") Тогда

ПолучитьСписок(СтруктураОтвет,СтруктураВхПараметров);

ИначеЕсли ВРег(СтруктураВхПараметров.ИмяМетода) = ВРег("Документ") Тогда

ПолучитьДокумент(СтруктураОтвет,СтруктураВхПараметров);

Иначе
ЗаполнитьСтруктуруОтвета(СтруктураОтвет,405,"Отсутствует Метод " + ?(СтруктураВхПараметров.ИмяМетода=Неопределено,"",СтруктураВхПараметров.ИмяМетода),ложь,"");
КонецЕсли;
Возврат СтруктураОтвет;
КонецФункции
//Заполняем структуру ответа
Процедура ЗаполнитьСтруктуруОтвета(СтруктураОтвет,КодОтвета,ТекстОшибки,Отработало,ДанныеОтвета)
СтруктураОтвет.КодОтвета  = КодОтвета;
СтруктураОтвет.ТекстОшибки = ТекстОшибки;
СтруктураОтвет.Отработало = Отработало;
СтруктураОтвет.ДанныеОтвета = ДанныеОтвета;
КонецПроцедуры

//МЕТОДЫ
Процедура ПолучитьСписок(СтруктураОтвет,СтруктураВхПараметров)
Результат = "Расходная накладная, 1, 01.01.2014
|Расходная накладная, 2, 01.01.2014";
СтруктураОтвет.ДанныеОтвета = Результат;
КонецПроцедуры

Процедура ПолучитьДокумент(СтруктураОтвет,СтруктураВхПараметров)
//ПраметрыЗапроса - number
ПарНомер = СтруктураВхПараметров.ПараметрыЗапроса.Получить("number");

Номер = Число(?(ПарНомер=Неопределено,0,ПарНомер));
Если Номер > 2 Тогда
ЗаполнитьСтруктуруОтвета(СтруктураОтвет,404,"Отсутствует документ с номером: " + Номер,ложь,"");
Иначе
Если Номер = 1 Тогда
Результат = "Расходная накладная, 1, 01.01.2014";
Иначе
Результат = "Расходная накладная, 2, 01.01.2014";
КонецЕсли;
СтруктураОтвет.ДанныеОтвета = Результат;
КонецЕсли;
КонецПроцедуры 

 

Как вы видите, размер кода увеличился, но стало гораздо проще добавлять новые методы.

Нужно просто добавить в проверку (PAPI_ОбработкаМетодовGET.PAPI_ОбработкаМетодовGET) новое имя метода и процедуру для этого метода.

По отладке HTTP-сервисов рекомендую статью с ИТС (https://its.1c.ru/db/metod8dev#content:5756:hdoc)

Первую часть заканчиваю. Мы рассмотрели с Вами как создать каркас для Get метода. В следующих частях поговорим про другие методы, про oData и JSON. Как и в этой статье будут примеры, но более  интересные.

Статьи из данного цикла:

HTTP Сервисы: Путь к своему сервису. Часть 2

HTTP Сервисы: Путь к своему сервису. Часть 3

HTTP Сервисы: Путь к своему сервису. Часть 4

22 Comments

  1. blackhole321
    Видно, что создано два Шаблона с методом Get, но по большому счету отличаются они только тем, что один ищет по номеру документ, а второй выводит все.

    Все это можно реализовать одним методом

    Возможно авторы хотели изолировать эти методы, чтобы было проще вносить правки в дальнейшем. Иначе, есть риск, что Ваш один метод со временем примет монстрообразный вид.

    Reply
  2. capitan
    «comcntr.dll» забываем как страшный сон!

    Напоминает Хрущева и его попытки засеять страну кукурузой.

    HTTP сервисы и COM совершенно разные технологии, нет смысла их противопоставлять.

    Начиная с того, что разные стороны выступают в логи ведущего.

    Делать все на HTTP так же бессмысленно, как и делать все на COM

    В вашей же терминологии- это как вдруг слетать на самолете на работу вместо того чтобы на маршрутке доехать

    Ну и маленькая ложечка дегтя — попробуйте тысяч десять строк передать по HTTP ,а потом порадуете сообщество быстродействием.

    если конечно индеец раньше не ляжет )

    Reply
  3. ArchLord42
    Важно: Хотелось бы обратить внимание на коды состояния из примера выше. Мне раза три в моей практике попадались API, которые всегда возвращали ответ с кодом 200 (200 OK («хорошо»)) и только в теле ответа, можно было понять, была ли ошибка. Это грубейшая ошибка разработчиков! Ну или это неуважение к конечному потребителю…

    Вообще-то это не фига не грубейшая ошибка и не неуважение к потребителю API, сразу видно что с построением архитектуры HTTP сервисов вы знакомы плохо, много где (в книгах, в блогах, на стэковерфлоу) уже давно разжеваны причины такого подхода.

    Простой пример: мы хотим получить данные учетной записи, отправляя запрос на account/{guid}

    Я запрашиваю /account/123, мне сервис возвращает { status: 400, msg: «incorrect guid» }, я точно понимаю, что я ввел не верный гуид

    Я запрашиваю /account/t140762c2-0742-4046-9a0e-c4f81931c549 мне возвращает { status: 404, msg: «account not found» }, я точно понимаю, что акка с таким гуидом нету

    Все что было выше — это ошибки БИЗНЕС логики

    А теперь я запрашиваю /accounttttt/t140762c2-0742-4046-9a0e-c4f81931c549

    и мне тупо возращается HTTP код 404 и тут я понимаю, что я накосячил с УРЛом

    Это ошибка транспорта HTTP

    Как итог: в первом и втором случае, запрос прошел корректно, сервер его корректно обработал и вернул ответ с ошибкой в бизнес логики.

    В третьем запросе, запрос не дошел даже до сервера, он его не обработал в принципе и я получил ошибку 404, а то, что коды ошибок совпадают с HTTP кодами, так это как раз из уважения к потребителям, т.к. примерно понятен смысл без всяких доп.сообщений, а постоянно возвращающийся ответ с 200 кодом, означает, что траспорт информации по HTTP от клиента до сервера прошел корректно и сервер его корректно обработал.

    ЗЫ. Конечно постоянно возвращать 200, даже когда на сервере произошла ошибка это предмет многих холиваров, вот например когда использование кодов является хорошим тоном.

    200 — тут все ясно

    400 — Bad Request, ошибка клиента — выдавать например при ошибке парсинга JSON (в случае когда он не валидиный) или это вообще не JSON

    401 — Unauthorized — тут думаю тоже все ясно,

    500 — Internal Server Error — Все необработанные ошибки сервера

    Reply
  4. capitan

    (3)+100500

    Reply
  5. CSiER

    (3)

    Вообще-то это не фига не грубейшая ошибка и не неуважение к потребителю API, сразу видно что с построением архитектуры HTTP сервисов вы знакомы плохо, много где (в книгах, в блогах, на стэковерфлоу) уже давно разжеваны причины такого подхода.

    Интерпретировать это как ошибку или нет зависит от того, как именно используется HTTP (только как транспорт или в качестве RESTful api), имхо. Ваш пример ближе к транспорту, у автора публикации — к REST.

    (3)

    ЗЫ. Конечно постоянно возвращать 200, даже когда на сервере произошла ошибка это предмет многих холиваров, вот например когда использование кодов является хорошим тоном.

    — аналогично, все зависит от того, как именно предполагается использовать API. На мой взгляд, здесь автор API решает как делать правильно (можно и 200 всегда возвращать и только get, а описание ошибки в ответе) — главное чтобы это все было хорошо описано, например, с помощью apiary.io.

    Reply
  6. addict2blood
    Самый главный минус. Нужно установить и настроить веб сервер

    Самый главный минус это выдача лицензий сервером 1С

    Reply
  7. Silenser

    (2)

    Ну и маленькая ложечка дегтя — попробуйте тысяч десять строк передать по HTTP ,а потом порадуете сообщество быстродействием.

    если конечно индеец раньше не ляжет )

    Как мне кажется, вопрос не в количестве строк, а в объеме пакета. В IIS ограничение, вроде бы, 30 Мб, хотя как утверждают некоторые разработчики на форумах, вопрос производительности начинает быть актуальным уже после 10 Мб. С вашей идеей в целом согласен, разные инструменты для разных задач.

    Reply
  8. capitan

    (6)все смешалось в доме облонских…

    на HTTP лицензия не расходуется

    Reply
  9. addict2blood

    (8) А я не писал, что HTTP лицензия расходуется.

    Только вот выдача лицензий сервером 1С тратит лицензию на каждое подключение. Запустил базу два раза — сожрал две лицензии. Запустил четыре базы — сожрал четыре лицензии.

    Reply
  10. dsdred

    (1)

    Возможно авторы хотели изолировать эти методы, чтобы было проще вносить правки в дальнейшем. Иначе, есть риск, что Ваш один метод со временем примет монстрообразный вид.

    Как раз таки монстрообразный вид это если сделать так как на ИТС пример написан.

    Приложу прин скрин 4-х летней давности, когда я только изучал веб-сервисы.

    В моем примере у каждого метода своя процедура, править легко.

    Reply
  11. dsdred

    (2)

    Напоминает Хрущева и его попытки засеять страну кукурузой.

    Забавное сравнение. Спасибо, посмеялся.

    Делать все на HTTP так же бессмысленно

    Я про все не говорю, но мне лично непонятны вот такие статьи (https://infostart.ru/public/827371/) от мая 2018,

    при чем радует, что статья ссылается на свежую статью 2012 года

    Ну и маленькая ложечка дегтя — попробуйте тысяч десять строк передать по HTTP ,а потом порадуете сообщество быстродействием.

    если конечно индеец раньше не ляжет )

    Дегтя не уловил. Специально глянул сейчас один из сервисов который делал для крупной сети. Смыл в том, что из УТ10 забираю данные раз в час по оптовому складу продажи за день и свободные остатки на текущий момент и там порядка 20К строк, забираю за 30-120 секунд.

    Вообще http-сервисы, как ниже было замечено ограничены не количеством строк а размером передаваемого сообщения, ограничение настроено на стороне веб сервера и в случае с IIS можно вот тут например посмотреть как его сделать больше или меньше (https://infostart.ru/public/427026/)

    Ну и так же никто не запрещает использовать порции. Ну и формат сообщения тоже влияет на объем, оптимально использовать JSON.

    П.С. Хотел в следующих частях про эти вещи говорить…

    Reply
  12. dsdred

    (9) Не понимаю к чему Вы это написали…

    Reply
  13. dsdred

    (3)

    В примере который я описал в статье труда не составит отрабатывать по Вашему.

    ЗаполнитьСтруктуруОтвета(СтруктураОтвет,200,»{«»status»»:404,»»msg»»:»»account not found»»}»,ложь,»»);

    Ну а вообще, отличить ошибку Бизнес логики от ошибки возвращаемой веб сервером, думаю труда не составит, но спорить с Вами не буду, так как

    это предмет многих холиваров
    Reply
  14. blackhole321

    (10)и..?

    Вы считаете более разумным запихнуть все из Вашего принтскрина в один метод?

    Reply
  15. dsdred

    (14) Если кратко ответить, то да. Что-то в GET, что-то в POST.

    А вообще то, что я считаю разумным у меня в процессе разработки.

    Reply
  16. WKBAPKA

    (8) я тоже читал, что при использовании HTTP лицензия расходуется, не расходуется при использовании WEB-Сервиса.

    Передавал каталог товаров в формате JSON, сервер Apache, пока с ограничением не столкнулся.

    Reply
  17. WKBAPKA

    Есть еще одно но при использовании HTTP, не все админы любят когда сервак где установлена 1С ка смотрит в мир и часто это дело закрывают. Поэтому достучаться можно только через внутреннюю сеть. Выходит, что надо тогда ставить отдельный сервак который будет смотреть в мир, иначе никак )

    Reply
  18. dsdred

    (17)

    Есть еще одно но при использовании HTTP, не все админы любят когда сервак где установлена 1С ка смотрит в мир и часто это дело закрывают. Поэтому достучаться можно только через внутреннюю сеть. Выходит, что надо тогда ставить отдельный сервак который будет смотреть в мир, иначе никак )

    Да еще есть мелочи и нюансы с которыми должны по идее справляться админы, к примеру организовать https. В моем текущем месте работы админы такие которые у нас административную часть спрашивают как сделать… Хуже этих слава богу еще не встречал.

    Reply
  19. WKBAPKA

    (18)https не поможет, если будут бомбить сервер

    Reply
  20. dsdred

    (19)Ну DDoS-атака это уже отдельный вопрос администрирования.

    Reply
  21. WKBAPKA

    (20)согласитесь, поставить отдельный сервачек будет дешевле, чем пытаться потом решать проблемы взлома сервера ?

    Reply
  22. dsdred

    (21)

    согласитесь, поставить отдельный сервачек будет дешевле, чем пытаться потом решать проблемы взлома сервера ?

    А кто спорит то? Согласен на все 100%.

    Вопрос обычно к жадности владельца бизнеса. Бывают случае когда скупой решает «Сэкономить» на персонале и железе в итоге затраты в разы выше если, что то случается.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *