504 gateway timeout


Ошибка под номером 504 наиболее распространена среди сайтов на просторах интернета. В подавляющем большинстве случаев пользователи видят надпись «504 Gateway Time-out (time out)» на белом фоне и уходят с сайта, не разбираясь в причинах потери работоспособности ресурса. Куда более неприятно видеть код 504 владельцам сайта, особенно если неизвестно какими причинами была вызвана ошибка и что нужно делать, чтобы её исправить.

Ошибка 504: причины и решение проблемы

Что означает ошибка «504 Gateway Time-out»

Ошибка 504 означает, что сервер, на котором расположен сайт, не успевает обработать запрос и вернуть в заданный лимит времени HTTP ответ пользователю. Чаще всего такая ситуация возникает при большой нагрузке на сервер: не имея возможности вовремя обрабатывать все запросы, сервер прерывает необработанные соединения по истечении установленного лимита времени. Если это происходит, вместо загрузки сайта пользователь видит на странице ошибку «504 Gateway Time-out».

Техническая сторона вопроса

В подавляющем большинстве случаев проблема с кодом 504 возникает:

  • если на сервере в качестве бэкенда установлен Apache;
  • при этом в качестве фронтенда установлен nginx.

Такое сочетание чаще всего генерирует ошибку 504 с примечанием Gateway Time-out. В такой связке nginx выступает в качестве чего-то вроде распределителя запросов пользователя, и они сначала попадают к нему, а не напрямую в Apache. И если из-за высокой нагрузки сервер Apache не смог вовремя ответить, nginx пошлёт пользователю соответствующий ответ в виде кода 504.

Из-за чего появляется ошибка 504

Появление ошибки 504 характерно для серверов Apache в случае большой нагрузки. Такие сервера имеют особенность: при поступлении большого количества запросов они не успевают обрабатываться. Всем пользователям, у которых браузеры не получили HTTP-ответ от сервера, будет показана ошибка 504 Gateway Time-out.

Сталкиваясь с проблемой большой нагрузки, Apache не сразу начинает отдавать код 504. Сначала все запросы, которые не могут быть обработаны прямо сейчас, выстраиваются в очередь. При превышении лимита времени на ожидание HTTP-ответа соединение разрывается, и только тогда появляется ошибка. Со стороны пользователя сайт будет пытаться загрузиться несколько секунд, но фактически загрузка не начинается, поскольку сервер не отвечает.


Из-за чего появляется ошибка 504 gateway time out

Ошибка на стороне скриптов

Иногда код «504 Gateway Tme-out» вызывает не чрезмерная нагрузка, а неправильная настройка скриптов на сайте. Любому скрипту отводится определённый отрезок времени на выполнение. На практике, по ряду причин, этого времени скрипту может не хватить.

Обычно скриптам не хватает времени на загрузку в том случае, если они располагаются на стороннем сервере. В свою очередь, такие сервера очень часто сами находятся под огромной нагрузкой (из-за того, что сотни и тысячи сайтов при каждом заходе пользователей подгружают определённый код). Если отведённое время истекает, но скрипт так и не получает ответ от сервера, он также может выдать ошибку 504.

Задержка в процессе выполнения скриптов на сайте может вызываться и другими причинами:

  1. Если скрипту для работы необходимы внешние ресурсы (к примеру, база данных на стороннем сервере), которая на данный момент недоступна.
  2. Если скрипт работает не напрямую, а с установкой соединения через прокси-сервер. В случае недоступности прокси-сервера или превышения времени ожидания ответа скрипт также выдаст код 504.
  3. Скрипт загружает данные со сторонних серверов, которые на данный момент недоступны.

Как объяснить появление ошибки 504 gateway time out

Как решить проблему 504

Точная последовательность действий для решения проблемы зависит от того, что именно привело к возникновению ошибки. Если причиной является слишком сильная нагрузка на сервер, можно попробовать предпринять следующие действия:

  1. Попробовать определить основные источники нагрузки на сервере. Нужно найти, какие именно запросы обрабатываются дольше всего и приводят к возникновению очереди и последующей ошибки 504, и оптимизировать эти места.
  2. Оптимизировать все скрипты. Желательно, чтобы загружаемые сайтом скрипты физически находились на том же сервере, что и сам сайт, или по крайней мере на физическом пространстве, находящемся под контролем владельца сайта. Если оптимизировать скрипты, настроить время их выполнения и выделить необходимые для этого серверные ресурсы, ошибка 504 перестанет возникать из-за скриптов.
  3. Можно пойти простым путём: просто увеличить ресурсы сервера, если есть такая возможность. Увеличение оперативной памяти, количества процессов httpd для Apache и другие меры повышения производительности приведут к тому, что серверу снова станет хватать ресурсов для выполнения запросов. Правда, подобное решение может являться лишь временной мерой, и с ростом нагрузки отсутствие должной оптимизации опять заявит о себе.

Решение ошибки 504 gateway time out

В том случае, если сайт с достаточно высокой посещаемостью (или требующий много ресурсов) располагается на обычном виртуальном хостинге, мощностей может элементарно не хватать. Некоторые хостеры присылают своим клиентам уведомления о превышении допустимой нагрузки, некоторые – нет. Следует посмотреть логи и запросить нужную информацию о технической поддержке хостинга. Вполне возможно, что с сайтом всё в порядке, просто из-за роста посещаемости пора переходить на VPS, VDS и другие тарифы и услуги с существенно большими ресурсами.

liveposts.ru

Я установил GitLab 6.0 в linux box и создал ряд проектов. Я могу создать локальный клон каждого проекта с использованием URL-адреса SSH, но когда я пытаюсь использовать URL-адрес HTTP, я получаю 504 Тайм-аут шлюза в считанные секунды.

  • Когда я вставляю URL-адрес HTTP в SourceTree, он говорит «Проверка источника» в течение секунды или около того, тогда «Это не допустимый путь/URL-адрес источника». Когда я нажимаю «Детали…», он говорит:

Ошибка запрашиваемого URL-адреса: 504 при доступе к http://myserver/group/project.git/info/refs

  • Git Gui также пытается получить доступ к URL http://myserver/group/project.git/info/refs и получает ошибку 504.

  • Когда я пытаюсь открыть этот URL-адрес «info/refs» в браузере, я получаю всплывающее окно » Аутентификация], который ** не принимает ** мое имя пользователя/пароль GitLab и электронная почта/пароль.

  • В плагине Eclise EGit есть поля для ввода имени пользователя и пароля — если я их заполню, тогда я получаю список ветвей, но затем я получаю «Проверенный тайм-аут» в операции клонирования (репо 2 Гб). Этот подход работает на небольших проектах на моем сервере GitLab.

В соответствии с инструкциями я использовал nginx, но, похоже, это источник ряда проблем, которые у меня есть.

sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production:

System information System: Ubuntu 12.04 Current User: git Using RVM: yes RVM Version: 1.6.9 Ruby Version: 1.9.3p0 Gem Version: 1.8.11 Bundler Version:1.3.5 Rake Version: 10.1.0 GitLab information Version: 6.0.0 Revision: 5246d63 Directory: /home/git/gitlab DB Adapter: mysql2 URL: http://myserver HTTP Clone URL: http://myserver/some-project.git SSH Clone URL: git@myserver:some-project.git Using LDAP: no Using Omniauth: no GitLab Shell Version: 1.7.0 Repositories: /home/git/repositories/ Hooks: /home/git/gitlab-shell/hooks/ Git: /usr/bin/git  

qa-help.ru

Что обозначает ошибка 504

Ошибка 504 Gateway Timeout означает истечение времени прохождения через шлюз. Пользователь может увидеть данный код ошибки в том случае, если сервер, работая в качестве прокси-сервера или шлюза, обратился к серверу, стоящему выше по иерархии, с запросом, но не получил вовремя ответ.

Сервера, у которых Apache установлен в качестве бэкенда, а nginx – фронтэнда, чаще всего генерируют данный код ошибки. Работа пользователя с сервером происходит по следующему плану: клиент отправляет запрос на сервер, который попадает не на прямую на Apache, а пересылается через nginx (это что-то вроде распределителя запросов). Если последний не смог получить ответ от Apache, за установленный промежуток времени, он отправляет клиенту вместо требуемого ему результата сообщение об ошибке сервера 504 (Gateway Timeout).

Причины появления ошибки

Нехватка ресурсов на сервере из-за большой нагрузки.

Сервер Apache имеет одну не очень приятную особенность – при большой нагрузке и нехватке ресурсов, он не успевает обрабатывать большое количество запросов и вовремя отдавать на них http-ответы. Таким образом, клиентские запросы выстраиваются в очередь, и когда лимит времени на получение ответа заканчивается, они сбрасываются ни с чем. Как следствие, пользователь видит на странице браузера код ошибки 504 (Gateway Timeout).


Следует учесть, что не всегда высокая нагрузка обусловлена большим числом посетителей, однако такое встречается не редко. Можете посмотреть статью «Ошибка 502 Bad Gateway — причины возникновения и способы устранения», там подробнее рассмотрены причины возникновения нагрузки.

Ошибки, допущенные в скриптах.

Еще одной причиной появления данной ошибки являются ошибки в исполняемых скриптах. Как правило на исполнение скрипта отводится определенное количество времени, но в некоторых случаях ему этого времени не хватает. Часто это бывает когда скрипт обращается к стороннему серверу и не всегда успевает отправить запрос и получить ответ в отведенный лимит времени и как следствие выдает ошибку.

Можно выделить следующие причины задержки исполнения скрипта:

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

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

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

Схема появления ошибки 504

Способы устранения ошибки 504


Рассмотрим несколько распространенных случаев и попытаемся понять как исправить 504 -ю ошибку.

Если шибка возникает из-за нагрузки на сервер, то в первую очередь необходимо предпринять следующие шаги:

1. Провести оптимизацию сервера.

2. Провести оптимизацию скриптов.

3. Увеличить доступные для сервера ресурсы (количество процессов httpd (Apache), оперативную память и т. п.)

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

Если вам нужен качественный виртуальных хостинг, можете обратить внимание на хостинг-провайдера HostLand, который предоставляет данную услугу в хорошем качестве.

Если есть подозрение на работу скриптов:

Нужно проверить на работоспособность ресурсы, к которым получают доступ скрипты. Очень часто проблема заключается именно в них. 


Стоит проверить, за какой период времени выполняются скрипты и укладываются ли они в отведенный лимит. Если необходимо, то в конфигурационном файле php.ini нужно увеличить значение php_max_execution_time. Этот параметр определяет время исполнения скрипта, обычно это 30 секунд, при необходимости можно установить 60.

Если хостинг не предоставляет возможности редактировать php.ini, можно попробовать прописать в файле htaccess следующую команду:

php_value max_execution_time N

N — в данном случае означает ожидание в секундах.

Но делать это через файл htaccess позволяют не все хостеры.

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

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

webmastermix.ru

Модуль Node.js os

Модуль os даёт доступ ко многим функциям, которые можно использовать для получения информации об операционной системе и об аппаратном обеспечении компьютера, на котором работает Node.js. Это стандартный модуль, устанавливать его не надо, для работы с ним из кода его достаточно подключить:

 const os = require('os')  

Здесь имеются несколько полезных свойств, которые, в частности, могут пригодиться при работе с файлами.

Так, свойство os.EOL позволяет узнать используемый в системе разделитель строк (признак конца строки). В Linux и macOS это n, в Windows — rn.

Надо отметить, что упоминая тут «Linux и macOS», мы говорим о POSIX-совместимых платформах. Ради краткости изложения менее популярные платформы мы тут не упоминаем.

Свойство os.constants.signals даёт сведения о константах, используемых для обработки сигналов процессов наподобие SIGHUP, SIGKILL, и так далее. Здесь можно найти подробности о них.

Свойство os.constants.errno содержит константы, используемые для сообщений об ошибках — наподобие EADDRINUSE, EOVERFLOW.

Теперь рассмотрим основные методы модуля os.

▍os.arch()

Этот метод возвращает строку, идентифицирующую архитектуру системы, например — arm, x64, arm64.

▍os.cpus()

Возвращает информацию о процессорах, доступных в системе. Например, эти сведения могут выглядеть так:

 [ { model: 'Intel(R) Core(TM)2 Duo CPU P8600 @ 2.40GHz',  speed: 2400,  times:  { user: 281685380,  nice: 0,  sys: 187986530,  idle: 685833750,  irq: 0 } },  { model: 'Intel(R) Core(TM)2 Duo CPU P8600 @ 2.40GHz',  speed: 2400,  times:  { user: 282348700,  nice: 0,  sys: 161800480,  idle: 703509470,  irq: 0 } } ]  

▍os.endianness()

Возвращает BE или LE в зависимости от того, какой порядок байтов (Big Engian или Little Endian) был использован для компиляции бинарного файла Node.js.

▍os.freemem()

Возвращает количество свободной системной памяти в байтах.

▍os.homedir()

Возвращает путь к домашней директории текущего пользователя. Например — '/Users/flavio'.

▍os.hostname()

Возвращает имя хоста.

▍os.loadavg()

Возвращает, в виде массива, данные о средних значениях нагрузки, вычисленные операционной системой. Эта информация имеет смысл только в Linux и macOS. Выглядеть она может так:

 [ 3.68798828125, 4.00244140625, 11.1181640625 ] 

▍os.networkInterfaces()

Возвращает сведения о сетевых интерфейсах, доступных в системе. Например:

 { lo0:  [ { address: '127.0.0.1',  netmask: '255.0.0.0',  family: 'IPv4',  mac: 'fe:82:00:00:00:00',  internal: true },  { address: '::1',  netmask: 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',  family: 'IPv6',  mac: 'fe:82:00:00:00:00',  scopeid: 0,  internal: true },  { address: 'fe80::1',  netmask: 'ffff:ffff:ffff:ffff::',  family: 'IPv6',  mac: 'fe:82:00:00:00:00',  scopeid: 1,  internal: true } ],  en1:  [ { address: 'fe82::9b:8282:d7e6:496e',  netmask: 'ffff:ffff:ffff:ffff::',  family: 'IPv6',  mac: '06:00:00:02:0e:00',  scopeid: 5,  internal: false },  { address: '192.168.1.38',  netmask: '255.255.255.0',  family: 'IPv4',  mac: '06:00:00:02:0e:00',  internal: false } ],  utun0:  [ { address: 'fe80::2513:72bc:f405:61d0',  netmask: 'ffff:ffff:ffff:ffff::',  family: 'IPv6',  mac: 'fe:80:00:20:00:00',  scopeid: 8,  internal: false } ] }  

▍os.platform()

Возвращает сведения о платформе, для которой был скомпилирован Node.js. Вот некоторые из возможных возвращаемых значений:

  • darwin
  • freebsd
  • linux
  • openbsd
  • win32

▍os.release()

Возвращает строку, идентифицирующую номер релиза операционной системы.

▍os.tmpdir()

Возвращает путь к заданной в системе директории для хранения временных файлов.

▍os.totalmem()

Возвращает общее количество системной памяти в байтах.

▍os.type()

Возвращает сведения, позволяющие идентифицировать операционную систему. Например:

  • Linux — Linux.
  • Darwin — macOS.
  • Windows_NT — Windows.

▍os.uptime()

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

Модуль Node.js events

Модуль events предоставляет нам класс EventEmitter, который предназначен для работы с событиями на платформе Node.js. Мы уже немного говорили об этом модуле в седьмой части этой серии материалов. Вот документация к нему. Здесь рассмотрим API этого модуля. Напомним, что для использования его в коде нужно, как это обычно бывает со стандартными модулями, его подключить. После этого надо создать новый объект EventEmitter. Выглядит это так:

 const EventEmitter = require('events') const door = new EventEmitter() 

Объект класса EventEmitter пользуется стандартными механизмами, в частности — следующими событиями:

  • newListener — это событие вызывается при добавлении обработчика событий.
  • removeListener — вызывается при удалении обработчика.

Рассмотрим наиболее полезные методы объектов класса EventEmitter (подобный объект в названиях методов обозначен как emitter).

▍emitter.addListener()

Псевдоним для метода emitter.on().

▍emitter.emit()

Генерирует событие. Синхронно вызывает все обработчики события в том порядке, в котором они были зарегистрированы.

▍emitter.eventNames()

Возвращает массив, который содержит зарегистрированные события.

▍emitter.getMaxListeners()

Возвращает максимальное число обработчиков, которые можно добавить к объекту класса EventEmitter. По умолчанию это 10. При необходимости этот параметр можно увеличить или уменьшить с использованием метода setMaxListeners().

▍emitter.listenerCount()

Возвращает количество обработчиков события, имя которого передаётся данному методу в качестве параметра:

 door.listenerCount('open') 

▍emitter.listeners()

Возвращает массив обработчиков события для соответствующего события, имя которого передано этому методу:

 door.listeners('open') 

▍emitter.off()

Псевдоним для метода emitter.removeListener(), появившийся в Node 10.

▍emitter.on()

Регистрируеn коллбэк, который вызывается при генерировании события. Вот как им пользоваться:

 door.on('open', () => {  console.log('Door was opened') }) 

▍emitter.once()

Регистрирует коллбэк, который вызывается только один раз — при первом возникновении события, для обработки которого зарегистрирован этот коллбэк. Например:

 const EventEmitter = require('events') const ee = new EventEmitter() ee.once('my-event', () => {  //вызвать этот коллбэк один раз при первом возникновении события }) 

▍emitter.prependListener()

При регистрации обработчика с использованием методов on() или addListener() этот обработчик добавляется в конец очереди обработчиков и вызывается для обработки соответствующего события последним. При использовании метода prependListener() обработчик добавляется в начало очереди, что приводит к тому, что он будет вызываться для обработки события первым.

▍emitter.prependOnceListener()

Этот метод похож на предыдущий. А именно, когда обработчик, предназначенный для однократного вызова, регистрируется с помощью метода once(), он оказывается последним в очереди обработчиков и последним вызывается. Метод prependOnceListener() позволяет добавить такой обработчик в начало очереди.

▍emitter.removeAllListeners()

Данный метод удаляет все обработчики для заданного события, зарегистрированные в соответствующем объекте. Пользуются им так:

 door.removeAllListeners('open') 

▍emitter.removeListener()

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

 const doSomething = () => {} door.on('open', doSomething) door.removeListener('open', doSomething) 

▍emitter.setMaxListeners()

Этот метод позволяет задать максимальное количество обработчиков, которые можно добавить к отдельному событию в экземпляре класса EventEmitter. По умолчанию, как уже было сказано, можно добавить до 10 обработчиков для конкретного события. Это значение можно изменить. Пользуются данным методом так:

 door.setMaxListeners(50) 

Модуль Node.js http

В восьмой части этой серии материалов мы уже говорили о стандартном модуле Node.js http. Он даёт в распоряжение разработчика механизмы, предназначенные для создания HTTP-серверов. Он является основным модулем, применяемым для решения задач обмена данными по сети в Node.js. Подключить его в коде можно так:

 const http = require('http') 

В его состав входят свойства, методы и классы. Поговорим о них.

▍Свойства

http.METHODS

В этом свойстве перечисляются все поддерживаемые методы HTTP:

 > require('http').METHODS [ 'ACL',  'BIND',  'CHECKOUT',  'CONNECT',  'COPY',  'DELETE',  'GET',  'HEAD',  'LINK',  'LOCK',  'M-SEARCH',  'MERGE',  'MKACTIVITY',  'MKCALENDAR',  'MKCOL',  'MOVE',  'NOTIFY',  'OPTIONS',  'PATCH',  'POST',  'PROPFIND',  'PROPPATCH',  'PURGE',  'PUT',  'REBIND',  'REPORT',  'SEARCH',  'SUBSCRIBE',  'TRACE',  'UNBIND',  'UNLINK',  'UNLOCK',  'UNSUBSCRIBE' ] 

http.STATUS_CODES

Здесь содержатся коды состояния HTTP и их описания:

 > require('http').STATUS_CODES { '100': 'Continue',  '101': 'Switching Protocols',  '102': 'Processing',  '200': 'OK',  '201': 'Created',  '202': 'Accepted',  '203': 'Non-Authoritative Information',  '204': 'No Content',  '205': 'Reset Content',  '206': 'Partial Content',  '207': 'Multi-Status',  '208': 'Already Reported',  '226': 'IM Used',  '300': 'Multiple Choices',  '301': 'Moved Permanently',  '302': 'Found',  '303': 'See Other',  '304': 'Not Modified',  '305': 'Use Proxy',  '307': 'Temporary Redirect',  '308': 'Permanent Redirect',  '400': 'Bad Request',  '401': 'Unauthorized',  '402': 'Payment Required',  '403': 'Forbidden',  '404': 'Not Found',  '405': 'Method Not Allowed',  '406': 'Not Acceptable',  '407': 'Proxy Authentication Required',  '408': 'Request Timeout',  '409': 'Conflict',  '410': 'Gone',  '411': 'Length Required',  '412': 'Precondition Failed',  '413': 'Payload Too Large',  '414': 'URI Too Long',  '415': 'Unsupported Media Type',  '416': 'Range Not Satisfiable',  '417': 'Expectation Failed',  '418': 'I'm a teapot',  '421': 'Misdirected Request',  '422': 'Unprocessable Entity',  '423': 'Locked',  '424': 'Failed Dependency',  '425': 'Unordered Collection',  '426': 'Upgrade Required',  '428': 'Precondition Required',  '429': 'Too Many Requests',  '431': 'Request Header Fields Too Large',  '451': 'Unavailable For Legal Reasons',  '500': 'Internal Server Error',  '501': 'Not Implemented',  '502': 'Bad Gateway',  '503': 'Service Unavailable',  '504': 'Gateway Timeout',  '505': 'HTTP Version Not Supported',  '506': 'Variant Also Negotiates',  '507': 'Insufficient Storage',  '508': 'Loop Detected',  '509': 'Bandwidth Limit Exceeded',  '510': 'Not Extended',  '511': 'Network Authentication Required' } 

http.globalAgent

Данное свойство указывает на глобальный экземпляр класса http.Agent. Он используется для управления соединениями. Его можно считать ключевым компонентом HTTP-подсистемы Node.js. Подробнее о классе http.Agent мы поговорим ниже.

▍Методы

http.createServer()

Возвращает новый экземпляр класса http.Server. Вот как пользоваться этим методом для создания HTTP-сервера:

 const server = http.createServer((req, res) => {  //в этом коллбэке будут обрабатываться запросы }) 

http.request()

Позволяет выполнить HTTP-запрос к серверу, создавая экземпляр класса http.ClientRequest.

http.get()

Этот метод похож на http.request(), но он автоматически устанавливает метод HTTP в значение GET и автоматически же вызывает команду вида req.end().

▍Классы

Модуль HTTP предоставляет 5 классов — Agent, ClientRequest, Server, ServerResponse и IncomingMessage. Рассмотрим их.

http.Agent

Глобальный экземпляр класса http.Agent, создаваемый Node.js, используется для управления соединениями. Он применяется в качестве значения по умолчанию всеми HTTP-запросами и обеспечивает постановку запросов в очередь и повторное использование сокетов. Кроме того, он поддерживает пул сокетов, что позволяет обеспечить высокую производительность сетевой подсистемы Node.js. При необходимости можно создать собственный объект http.Agent.

http.ClientRequest

Объект класса http.ClientRequest, представляющий собой выполняющийся запрос, создаётся при вызове методов http.request() или http.get(). При получении ответа на запрос вызывается событие response, в котором передаётся ответ — экземпляр http.IncomingMessage. Данные, полученные после выполнения запроса, можно обработать двумя способами:

  • Можно вызвать метод response.read().
  • В обработчике события response можно настроить прослушиватель для события data, что позволяет работать с потоковыми данными.

http.Server

Экземпляры этого класса используются для создания серверов с применением команды http.createServer(). После того, как у нас имеется объект сервера, мы можем воспользоваться его методами:

  • Метод listen() используется для запуска сервера и организации ожидания и обработки входящих запросов.
  • Метод close() останавливает сервер.

http.ServerResponse

Этот объект создаётся классом http.Server и передаётся в качестве второго параметра событию request при его возникновении. Обычно подобным объектам в коде назначают имя res:

 const server = http.createServer((req, res) => {  //res - это объект http.ServerResponse }) 

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

Вот методы, которые используются для работы с HTTP-заголовками:

  • getHeaderNames() — возвращает список имён установленных заголовков.
  • getHeaders() — возвращает копию установленных HTTP-заголовков.
  • setHeader('headername', value) — устанавливает значение для заданного заголовка.
  • getHeader('headername') — возвращает установленный заголовок.
  • removeHeader('headername') — удаляет установленный заголовок.
  • hasHeader('headername') — возвращает true если в ответе уже есть заголовок, имя которого передано этому методу.
  • headersSent() — возвращает true если заголовки уже отправлены клиенту.

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

Для отправки данных клиенту в теле ответа используют метод write(). Он отправляет буферизованные данные в поток HTTP-ответа.

Если до этого заголовки ещё не были установлены командой response.writeHead(), сначала будут отправлены заголовки с кодом состояния и сообщением, которые заданы в запросе. Задавать их значения можно, устанавливая значения для свойств statusCode и statusMessage:

 response.statusCode = 500 response.statusMessage = 'Internal Server Error' 

http.IncomingMessage

Объект класса http.IncomingMessage создаётся в ходе работы следующих механизмов:

  • http.Server — при обработке события request.
  • http.ClientRequest — при обработке события response.

Его можно использовать для работы с данными ответа. А именно:

  • Для того чтобы узнать код состояния ответа и соответствующее сообщение используются свойства statusCode и statusMessage.
  • Заголовки ответа можно посмотреть, обратившись к свойству headers или rawHearders (для получения списка необработанных заголовков).
  • Метод запроса можно узнать, воспользовавшись свойством method.
  • Узнать используемую версию HTTP можно с помощью свойства httpVersion.
  • Для получения URL предназначено свойство url.
  • Свойство socket позволяет получить объект net.Socket, связанный с соединением.

Данные ответа представлены в виде потока так как объект http.IncomingMessage реализует интерфейс Readable Stream.

Работа с потоками в Node.js

Потоки — это одна из фундаментальных концепций, используемых в Node.js-приложениях. Потоки — это инструменты, которые позволяют выполнять чтение и запись файлов, организовывать сетевое взаимодействие систем, и, в целом — эффективно реализовывать операции обмена данными.

Концепция потоков не уникальна для Node.js. Они появились в ОС семейства Unix десятки лет назад. В частности, программы могут взаимодействовать друг с другом, передавая потоки данных с использованием конвейеров (с применением символа конвейера — |).

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

Благодаря использованию механизма потоков файлы можно считывать и обрабатывать по частям, что избавляет от необходимости хранить в памяти большие объёмы данных.

Модуль Node.js stream представляет собой основу, на которой построены все API, поддерживающие работу с потоками.

▍О сильных сторонах использования потоков

Потоки, в сравнении с другими способами обработки данных, отличаются следующими преимуществами:

  • Эффективное использование памяти. Работа с потоком не предполагает хранения в памяти больших объёмов данных, загружаемых туда заранее, до того, как появится возможность их обработать.
  • Экономия времени. Данные, получаемые из потока, можно начать обрабатывать гораздо быстрее, чем в случае, когда для того, чтобы приступить к их обработке, приходится ждать их полной загрузки.

▍Пример работы с потоками

Традиционный пример работы с потоками демонстрирует чтение файла с диска.

Сначала рассмотрим код, в котором потоки не используются. Стандартный модуль Node.js fs позволяет прочитать файл, после чего его можно передать по протоколу HTTP в ответ на запрос, полученный HTTP-сервером:

 const http = require('http') const fs = require('fs') const server = http.createServer(function (req, res) {  fs.readFile(__dirname + '/data.txt', (err, data) => {  res.end(data)  }) }) server.listen(3000) 

Метод readFile(), использованный здесь, позволяет прочесть файл целиком. Когда чтение будет завершено, он вызывает соответствующий коллбэк.

Метод res.end(data), вызываемый в коллбэке, отправляет содержимое файла клиенту.

Если размер файла велик, то эта операция займёт немало времени. Вот тот же пример переписанный с использованием потоков:

 const http = require('http') const fs = require('fs') const server = http.createServer((req, res) => {  const stream = fs.createReadStream(__dirname + '/data.txt')  stream.pipe(res) }) server.listen(3000) 

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

▍Метод pipe()

В предыдущем примере мы использовали конструкцию вида stream.pipe(res), в которой вызывается метод файлового потока pipe(). Этот метод берёт данные из их источника и отправляет их в место назначения.

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

Возвращаемым значением метода pipe() является целевой поток. Это очень удобно, так как позволяет объединять в цепочки несколько вызовов метода pipe():

 src.pipe(dest1).pipe(dest2) 

Это равносильно такой конструкции:

 src.pipe(dest1) dest1.pipe(dest2) 

▍API Node.js, в которых используются потоки

Потоки — полезный механизм, в результате многие модули ядра Node.js предоставляют стандартные возможности по работе с потоками. Перечислим некоторые из них:

  • process.stdin — возвращает поток, подключённый к stdin.
  • process.stdout — возвращает поток, подключённый к stdout.
  • process.stderr — возвращает поток, подключённый к stderr.
  • fs.createReadStream() — создаёт читаемый поток для работы с файлом.
  • fs.createWriteStream()— создаёт записываемый поток для работы с файлом.
  • net.connect() — инициирует соединение, основанное на потоке.
  • http.request() — возвращает экземпляр класса http.ClientRequest, предоставляющий доступ к записываемому потоку.
  • zlib.createGzip() — сжимает данные с использованием алгоритма gzip и отправляет их в поток.
  • zlib.createGunzip() — выполняет декомпрессию gzip-потока.
  • zlib.createDeflate() — сжимает данные с использованием алгоритма deflate и отправляет их в поток.
  • zlib.createInflate() — выполняет декомпрессию deflate-потока.

▍Разные типы потоков

Существует четыре типа потоков:

  • Поток для чтения (Readable) — это поток, из которого можно читать данные. Записывать данные в такой поток нельзя. Когда в такой поток поступают данные, они буферизуются до того момента пока потребитель данных не приступит к их чтению.
  • Поток для записи (Writable) — это поток, в который можно отправлять данные. Читать из него данные нельзя.
  • Дуплексный поток (Duplex) — в такой поток можно и отправлять данные и читать их из него. По существу это — комбинация потока для чтения и потока для записи.
  • Трансформирующий поток (Transform) — такие потоки похожи на дуплексные потоки, разница заключается в том, что то, что поступает на вход этих потоков, преобразует то, что из них можно прочитать.

▍Создание потока для чтения

Поток для чтения можно создать и инициализировать, воспользовавшись возможностями модуля stream:

 const Stream = require('stream') const readableStream = new Stream.Readable() 

Теперь в поток можно поместить данные, которые позже сможет прочесть потребитель этих данных:

 readableStream.push('hi!') readableStream.push('ho!') 

▍Создание потока для записи

Для того чтобы создать записываемый поток нужно расширить базовый объект Writable и реализовать его метод _write(). Для этого сначала создадим соответствующий поток:

 const Stream = require('stream') const writableStream = new Stream.Writable() 

Затем реализуем его метод _write():

 writableStream._write = (chunk, encoding, next) => {  console.log(chunk.toString())  next() } 

Теперь к такому потоку можно подключить поток, предназначенный для чтения:

 process.stdin.pipe(writableStream) 

▍Получение данных из потока для чтения

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

 const Stream = require('stream') const readableStream = new Stream.Readable() const writableStream = new Stream.Writable() writableStream._write = (chunk, encoding, next) => {  console.log(chunk.toString())  next() } readableStream.pipe(writableStream) readableStream.push('hi!') readableStream.push('ho!') readableStream.push(null) 

Команда readableStream.push(null) сообщает об окончании вывода данных.

Работать с потоками для чтения можно и напрямую, обрабатывая событие readable:

 readableStream.on('readable', () => {  console.log(readableStream.read()) }) 

▍Отправка данных в поток для записи

Для отправки данных в поток для записи используется метод write():

 writableStream.write('hey!n') 

▍Сообщение потоку для записи о том, что запись данных завершена

Для того чтобы сообщить потоку для записи о том, что запись данных в него завершена, можно воспользоваться его методом end():

 writableStream.end() 

Этот метод принимает несколько необязательных параметров. В частности, ему можно передать последнюю порцию данных, которые надо записать в поток.

Основы работы с MySQL в Node.js

MySQL является одной из самых популярных СУБД в мире. В экосистеме Node.js имеется несколько пакетов, которые позволяют взаимодействовать с MySQL-базами, то есть — сохранять в них данные, получать данные из баз и выполнять другие операции.

Мы будем использовать пакет mysqljs/mysql. Этот проект, который существует уже очень давно, собрал более 12000 звёзд на GitHub. Для того чтобы воспроизвести следующие примеры, вам понадобится MySQL-сервер.

▍Установка пакета

Для установки этого пакета воспользуйтесь такой командой:

 npm install mysql 

▍Инициализация подключения к базе данных

Сначала подключим пакет в программе:

 const mysql = require('mysql') 

После этого создадим соединение:

 const options = {  user: 'the_mysql_user_name',  password: 'the_mysql_user_password',  database: 'the_mysql_database_name' } const connection = mysql.createConnection(options) 

Теперь попытаемся подключиться к базе данных:

 connection.connect(err => {  if (err) {  console.error('An error occurred while connecting to the DB')  throw err  } } 

▍Параметры соединения

В вышеприведённом примере объект options содержал три параметра соединения:

 const options = {  user: 'the_mysql_user_name',  password: 'the_mysql_user_password',  database: 'the_mysql_database_name' } 

На самом деле этих параметров существует гораздо больше. В том числе — следующие:

  • host — имя хоста, на котором расположен MySQL-сервер, по умолчанию — localhost.
  • port — номер порта сервера, по умолчанию — 3306.
  • socketPath — используется для указания сокета Unix вместо хоста и порта.
  • debug — позволяет работать в режиме отладки, по умолчанию эта возможность отключена.
  • trace — позволяет выводить сведения о трассировке стека при возникновении ошибок, по умолчанию эта возможность включена.
  • ssl — используется для настройки SSL-подключения к серверу.

▍Выполнение запроса SELECT

Теперь всё готово к выполнению SQL-запросов к базе данных. Для выполнения запросов используется метод соединения query, который принимает запрос и коллбэк. Если операция завершится успешно — коллбэк будет вызван с передачей ему данных, полученных из базы. В случае ошибки в коллбэк попадёт соответствующий объект ошибки. Вот как это выглядит при выполнении запроса на выборку данных:

 connection.query('SELECT * FROM todos', (error, todos, fields) => {  if (error) {  console.error('An error occurred while executing the query')  throw error  }  console.log(todos) }) 

При формировании запроса можно использовать значения, которые будут автоматически встроены в строку запроса:

 const id = 223 connection.query('SELECT * FROM todos WHERE id = ?', [id], (error, todos, fields) => {  if (error) {  console.error('An error occurred while executing the query')  throw error  }  console.log(todos) }) 

Для передачи в запрос нескольких значений можно, в качестве второго параметра, использовать массив:

 const id = 223 const author = 'Flavio' connection.query('SELECT * FROM todos WHERE id = ? AND author = ?', [id, author], (error, todos, fields) => {  if (error) {  console.error('An error occurred while executing the query')  throw error  }  console.log(todos) }) 

▍Выполнение запроса INSERT

Запросы INSERT используются для записи данных в базу. Например, запишем в базу данных объект:

 const todo = {  thing: 'Buy the milk'  author: 'Flavio' } connection.query('INSERT INTO todos SET ?', todo, (error, results, fields) => {  if (error) {  console.error('An error occurred while executing the query')  throw error  } }) 

Если у таблицы, в которую добавляются данные, есть первичный ключ со свойством auto_increment, его значение будет возвращено в виде results.insertId:

 const todo = {  thing: 'Buy the milk'  author: 'Flavio' } connection.query('INSERT INTO todos SET ?', todo, (error, results, fields) => {  if (error) {  console.error('An error occurred while executing the query')  throw error  }}  const id = results.resultId  console.log(id) ) 

▍Закрытие соединения с базой данных

После того как работа с базой данных завершена и пришло время закрыть соединение — воспользуйтесь его методом end():

 connection.end() 

Это приведёт к правильному завершению работы с базой данных.

О разнице между средой разработки и продакшн-средой

Создавая приложения в среде Node.js можно использовать различные конфигурации для окружения разработки и продакшн-окружения.

По умолчанию платформа Node.js работает в окружении разработки. Для того чтобы указать ей на то, что код выполняется в продакшн-среде, можно настроить переменную окружения NODE_ENV:

 NODE_ENV=production 

Обычно это делается в командной строке. В Linux, например, это выглядит так:

 export NODE_ENV=production 

Лучше, однако, поместить подобную команду в конфигурационный файл наподобие .bash_profile (при использовании Bash), так как в противном случае такие настройки не сохраняются после перезагрузки системы.

Настроить значение переменной окружения можно, воспользовавшись следующей конструкцией при запуске приложения:

 NODE_ENV=production node app.js 

Эта переменная окружения широко используется во внешних библиотеках для Node.js. Установка NODE_ENV в значение production обычно означает следующее:

  • До минимума сокращается логирование.
  • Используется больше уровней кэширования для оптимизации производительности.

Например, Pug — библиотека для работы с шаблонами, используемая Express, готовится к работе в режиме отладки в том случае, если переменная NODE_ENV не установлена в значение production. Представления Express, в режиме разработки, генерируются при обработке каждого запроса. В продакшн-режиме они кэшируются. Есть и множество других подобных примеров.

Express предоставляет конфигурационные хуки для каждого окружения. То, какой именно будет вызван, зависит от значения NODE_ENV:

 app.configure('development', () => {  //... }) app.configure('production', () => {  //... }) app.configure('production', 'staging', () => {  //... }) 

Например, с их помощью можно использовать различные обработчики событий для разных режимов:

 app.configure('development', () => {  app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); }) app.configure('production', () => {  app.use(express.errorHandler()) }) 

habrparser.blogspot.com

Что значит 504 gateway time out Nginx?

504 gateway timeout

Как я уже сказал, такая ошибка возникает, когда сервер Nginx работает в режиме прокси. Например, при использовании php-fpm или Apache. Дословно, она означает, что превышено время ожидания ответа от сервера. В нашем случае, превышено время ожидания ответа от php-fpm. Рассмотрим несколько причин такого поведения:

  • Скрипт PHP или на другом языке полностью завис и уже не вернет никакого ответа;
  • Скрипт работает очень долго, но в Nginx настроен интервал на сброс соединения если целевой сервер не ответил на запрос за отведенный строк;
  • Сервер перегружен и не успевает обслужить всех клиентов, вернуть ответы на все запросы Nginx;

Дальше рассмотрим что можно сделать если вы встретились с ошибкой 504 gateway time out Nginx.

Как исправить 504 gateway time out Nginx?

Самый первый вариант — это если вашему серверу, php-fpm или apache не хватает ресурсов системы, например, памяти или процессора. Вы можете посмотреть свободную память с помощью команды free:

free -h

504 gateway timeout

Нагрузку на процессор можно узнать командой htop:

htop

504 gateway timeout

Естественно, если вы видите, что PHP занимает все процессорное время, то значит проблема в ресурсах сервера. Вы можете покопаться в движке своего сайта, пытаться оптимизировать те или иные моменты, об этом будет отдельная статья или же выбрать более мощный VPS сервер.

Второй вариант — это если так и было запланировано, чтобы скрипт работал долго. В таком случае нужно настроить Nginx, чтобы он дождался ответа от Apache или php-fpm. Для решения проблемы в случае с php-fpm нужно только добавить две строчки в блок настройки fastgci:

fastcgi_send_timeout 300;
fastcgi_read_timeout 300;

504 gateway timeout

Здесь 300 означает 300 секунд, для большинства скриптов, этого будет вполне достаточно, но вы можете еще больше увеличить значение если это нужно. Также ошибка 504 может возникать, когда Nginx используется в качестве прокси для Apache или любого другого веб-сервера, тогда нужно еще настроить время ожидания для прокси. Добавьте эти строки в секцию server:

proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
send_timeout 600;

Тут уже мы задаем таймаут 600 секунд для различных видов действий — подключения, отправки данных, чтения данных и так далее. После завершения настройки Nginx стоит перезапустить:

sudo systemctl restart nginx

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

fgrep -i " 504 " /var/log/nginx/access.log

Более подробную информацию иногда можно увидеть в error.log:

fgrep -i " 504 " /var/log/nginx/error.log

Дальше, если проблема именно в php-fpm, вы можете отследить какие скрипты выполняются медленно с помощью встроенной функции slow-log. Для ее активации добавьте следующие строки в конфигурацию вашего пула:

sudo vi /etc/php-fpm.d/www.conf

slowlog = /var/log/php-fpm/www-slow.log
request_slowlog_timeout = 5s

504 gateway timeout

 

Здесь 5 секунд, означает, что в лог файл будут добавляться скрипты, которые выполняются дольше пяти секунд. Вы можете менять это значение по своему усмотрению. В логе вы сможете увидеть не только сами скрипты, но и трассировку методов, которые привели к проблемам:

504 gateway timeout

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

Выводы

В этой статье мы рассмотрели как исправить 504 gateway time out Nginx 1.2 7, а также почему может возникнуть эта ошибка. Надеюсь, эта информация была полезной для вас.

losst.ru

Что значит ошибка 504 Gateway Timeout (time out)?

Ошибка 504 Gateway Timeout (time out) — одна из самых распространенных. Что же такое — 504 Gateway Timeout (time out)? Как правило, подобного рода ошибка может возникать в том случае, если на сервер, на котором находится какой-то веб-ресурс, посылается огромное количество запросов, и он просто не успевает их обрабатывать, то есть у него не получается в установленный лимит времени вернуть HTTP-ответ. Вследствие этого может даже прерываться соединение, а пользователь так и не получит доступ к веб-ресурсу. Это обусловлено тем, что сервер не успевает обрабатывать старые запросы, которых накопилось уже много, а появляются еще и новые, которые встают в очередь и не успевают обрабатываться.

Как устранить ошибку 504 Gateway Timeout (time out)?

Проблема может заключаться еще и в скрипте, который не успевает справиться с поставленной задачей за отведенное ему время. В большинстве случаев это происходит тогда, когда скрипт обращается к сторонним узлам. Для того чтобы решить такую проблему, достаточно увеличить значение параметра PHP max_execution_time. Если проблема не будет решена, тогда придется каким-либо образом оптимизировать сам скрипт, чтобы он смог выполнять задачи за установленное время.

Справиться с насущной проблемой может только администратор сервера, который должен увеличить его производительность в несколько раз. Осуществить задуманное можно только если увеличить количество оперативной памяти компьютера, а также сменить процессор на более мощный. Кроме того, потребуется увеличить количество процессов httpd непосредственно в среде Apache. Может случиться и такое, что сайту вообще придется «переехать» на другой хостинг. Такая необходимость возникнет только в том случае, если сайт будет располагаться на обычном виртуальном хостинге, администратор которого либо не будет отвечать на запросы, либо откажется от помощи или если у него не получится решить такую проблему.

Существует еще один вариант решения, который, возможно, придется по душе большей части пользователей. Этот вариант подразумевает оптимизацию непосредственно самого сайта. То есть администратору сайта потребуется оптимизировать скрипты, SQL-запросы и многое другое для того чтобы они смогли выполняться за меньшее количество времени.

www.kakprosto.ru

Если сервер, на котором располагается ваш ресурс, перегружен (это происходит вследствие исчерпывания лимита трафика), он выдает пользователю сообщение: «Ошибка 504 gateway time out». В переводе на русский это означает: «время ответа шлюза вышло, шлюз не отвечает». Возникает ситуация, когда Apache чисто физически не может обработать все http-запросы, и они встают в очередь. Однако проходит лимитное время, и приходит сообщение о том, что запрос не обработан.ошибка 504

Чтобы исправить ситуацию, необходимо оптимизировать ваш сервер. Для этого нужно изменить объем оперативной памяти и количество запросов http (Apache) в сторону их увеличения. Еще один вариант — оптимизировать работоспособность всех скриптов, находящихся на вашем сайте. Данная операция поможет поднять производительность обработки. 

Если же вы оплачиваете свой хостинг, то следует сразу же обратиться за помощью в саппорт. Служба поддержки обязана проверить ваш сайт на наличие каких-то неисправностей и при возможности «отремонтировать» его. Не стоит пренебрегать такой возможностью. «Дырок», которые необходимо залатать, может быть больше, чем вы думаете. Некоторые хостинг-провайдеры осуществляют техническую поддержку по телефону. Данный вид помощи очень полезен, если вы в первый раз столкнулись с такими техническими проблемами, как ошибка 504. Благодаря такому саппорту вы сможете научиться устранять их самостоятельно, без посторонней помощи.

ошибка 504 gateway time outЕсть и еще одна причина, по которой может возникнуть 504-ошибка: скрипт, выполняющий какую-то команду, не укладывается в те временные рамки, которые для него заданы. Это может быть связано с запросом сторонних ресурсов, либо он сам в это время занимается другим делом. Например, выстраивает поисковый индекс.
Для удаления неисправности вы можете пойти двумя путями:
1) облегчить скрипт путем его оптимизации;
2) увеличить значение PHP-параметра max_execution_time.
Еще раз хотелось бы затронуть вопрос о технической поддержке хостинг-провайдера, на котором расположен ваш сайт. Безусловно, у каждого он свой, но обязанности саппортов для всех обязательны. Бывают такие случаи, когда вопросы, отправленные в службу поддержки, остаются без внимания. Особенно если это касается каких-нибудь лагов. Например, возникает та же самая ошибка 504. В этом случае меняйте хостинг. Если начнутся более серьезные проблемы, то вряд ли вы сможете рассчитывать на их помощь.

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

Вот и все, что хотелось вам рассказать о таком явлении, как ошибка 504. Пускай она встречается вам как можно реже!

fb.ru


You May Also Like

About the Author: admind

Добавить комментарий

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

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.