Бот telegram webhook — Урок 4. Вебхуки
Урок 4. Вебхуки.
С простым ботом наконец-то разобрались, теперь будем осваивать различные «плюшки». Первая из них и, пожалуй, самая главная, — вебхуки.
А в чём, собственно, разница?
Давайте для начала разберемся, как боты принимают сообщения. Первый и наиболее простой вариант заключается в периодическом опросе серверов Telegram на предмет наличия новой информации. Всё это осуществляется через т.н. Long Polling, т.е. открывается соединение на непродолжительное время и все обновления тут же прилетают боту. Просто, но не очень надежно. Во-первых, серверы Telegram периодически начинают возвращать ошибку 504 (Gateway Timeout), из-за чего некоторые боты впадают в ступор. Даже pyTelegramBotAPI, используемый мной, не всегда может пережить такое.Во-вторых, если одновременно запущено несколько ботов, вероятность столкнуться с ошибками возрастает. Это вдвойне обидно, если сами боты используются не очень часто.
Вебхуки работают несколько иначе. Устанавливая вебхук, вы как бы говорите серверам Telegram: «Слышь, если кто мне напишет, стукни сюда — (ссылка)». Отпадает необходимость периодически самому опрашивать серверы, тем самым, исчезает неприятная причина падений ботов. Однако за это приходится платить необходимостью установки полноценного веб-сервера на ту машину, на которой планируется запускать ботов. Что ещё неприятно, надо иметь собственный SSL-сертификат, т.к. вебхуки в телеграме работают только по HTTPS. К счастью, в один прекрасный день появилась поддержка самоподписанных сертификатов. Вот об их применении я и расскажу.
Создаем сертификат
Повторяю: я не считаю себя супер-мега-крутым специалистом в айти, возможно, я что-то делаю неправильно, тем не менее, это работает и выглядит вполне прилично. Ладно, приступим.Для начала, установим пакет openssl (для Linux): sudo apt-get install openssl
.Затем сгенерируем приватный ключ: openssl genrsa -out webhook_pkey.pem 2048
Теперь, внимание, генерируем самоподписанный сертификат вот этой вот длинной командой: openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem
После этой команды нам предложат ввести некоторую информацию о себе: двухбуквенный код страны, имя организации и т.д. Если не хотите ничего вводить, ставьте точку. НО! ВАЖНО! Когда дойдете до предложения ввести Common Name, следует написать IP адрес сервера, на котором будет запущен бот.

В результате получим файлы webhook_cert.pem
и webhook_pkey.pem
, положим их в какой-нибудь пустой каталог, в котором потом будем создавать бота. Сертификаты готовы, теперь займемся ботом. Чтобы не сильно загружать себе мозги, напишем простой echo-bot из урока № 1, только теперь с использованием сертификата.
Наш вишнёвый сервер
Выше я упомянул необходимость наличия веб-сервера, для работы с вебхуками. Те, кто умело владеет Apache или Nginx, можете дальше не читать. Лично я никак не мог (и не могу до сих пор) понять, как обрабатывать входящие сообщения от этих серверов в Python. Поэтому, было принято простое и довольно эффективное решение — используем веб-фреймворк CherryPy. Это не самый простой фреймворк по сравнению, например, с Flask, но мы будем использовать именно его.Итак, установим CherryPy простой командой python3.4 -m pip install cherrypy
.
Новый старый бот
Перейдем в каталог с нашими сертификатами и создадим файлы bot.py
и config.py
. В последнем создадим переменную token, в которую передадим токен нашего бота. Открываем bot.py
.Импортируем 2 библиотеки, зададим необходимые константы и создадим экземпляр бота:
Обратите внимание, что Telegram поддерживает всего 4 различных порта при работе с самоподписанными сертификатами. Теоретически, это означает, что на одной машине может быть запущено не больше 4 ботов на вебхуках. Практически, это поправимо, но об этом — в следующий раз.
Создадим класс, реализующий экземпляр веб-сервера. Это, в принципе, стандартный код, который от бота к боту сильно меняться не будет:
Обратите внимание на название функции: index
. Это, по сути, обозначает последнюю часть url. Поясню на примере: если бы мы хотели получать обновления на адрес 80.100.95.20/webhooksbot
, то функцию выше мы бы назвали webhooksbot
. index — это аналог отсутствия какой-либо дополнительной маршрутизации. Зачем менять это значение на другое, рассказано здесь, сейчас это не нужно.Итак, что мы видим в коде выше? Принимаем входящие запросы по URL наш.ip.адрес/
, получаем содержимое и прогоняем через набор хэндлеров. Кстати, о них. Т.к. мы реализуем простейших echo-бот, хэндлер нам нужен всего один (такой же, как и в уроке 1.5):
Внимательный читатель всё же заметит одно отличие, о котором я говорить не буду 😉 Заодно ещё один повод открыть документацию.
Далее, отправим серверу наш самоподписанный сертификат и «обратный адрес», по которому просим сообщать обо всех новых сообщениях:
Наконец, укажем настройки нашего сервера и запустим его!
Обратите внимание на последнюю строку. Наш сервер в качестве «корня» будет прослушивать адрес вида «ip-адрес/токен_бота», относительно которого index — это и есть этот адрес. Может, немного криво пояснил, но позднее вам всё станет предельно ясно, сейчас не нужно загромождать голову лишней информацией.
Запустим бота и напишем ему парочку сообщений. Затем посмотрим в окно терминала:

Если код статуса равен 200 (OK), значит, всё в порядке и бот получил сообщения от сервера.