Запретить получение старых обновлений из Telegram Bot API с помощью веб-ловушки

Я пишу бота для Telegram и использую официальный API бота. У меня есть сервер веб-перехватчиков, который обрабатывает запросы и отправляет 200 OK ответ на каждый запрос.

Перед остановкой сервера веб-перехватчик отключается, поэтому Telegram больше не отправляет обновления. Однако всякий раз, когда я включаю бота и снова устанавливаю URL-адрес веб-перехватчика, Telegram начинает наводнять сервер веб-перехватчика старыми обновлениями.

Есть ли способ предотвратить это, не запрашивая повторно /getUpdates, пока я не дойду до последнего обновления?

Вот сильно упрощенная версия того, как выглядит мой код:

var http = require('http'),
    unirest = require('unirest'),
    token = '***';

// Attach the webhook
unirest.post('https://api.telegram.org/bot' + token + '/setWebhook')
    .field('url', 'https://example.com/api/update')
    .end();

process.on('exit', function() {
    // Detach the webhook
    unirest.post('https://api.telegram.org/bot' + token + '/setWebhook')
        .field('url', '')
        .end();
});

// Handle requests
var server = http.createServer(function(req, res) {
    res.writeHead(200, { 'Content-Type': 'text/plain' })
    res.end('Thanks!');
});

server.listen(80);

Заранее спасибо.


person Community    schedule 29.07.2015    source источник


Ответы (4)


При запуске сервера вы можете записать метку времени, а затем использовать ее для сравнения со значениями date входящего сообщения. Если дата> = отметка времени при запуске ... сообщение можно обработать.

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

person Chris Brand    schedule 29.07.2015
comment
Да: дата - это поле объекта сообщения: core.telegram.org/bots/api#message В режиме веб-перехватчиков нет возможности фильтровать по update_id / дате: core. telegram.org/bots/api#getting-updates, поэтому отфильтровать старые даты - это решение IMMO. Кстати, я написал обработчик веб-перехватчиков на Ruby: github.com/solyaris/BOTServer - person Giorgio Robino; 01.12.2015

Лучше всего использовать update_id, который представляет собой конкретное число, которое увеличивается при каждом новом запросе (т. Е. Обновлении). Как это реализовать?

Во-первых, давайте начнем со следующего анонимного класса (используя PHP7):

$lastUpdateId = new class()
{
    const FILE_PATH = "last-update-id.txt";
    private $value = 1;

    public function __construct()
    {
        $this->ensureFileExists();
        $this->value = filesize(self::FILE_PATH) == 0
            ? 0 : (int)(file_get_contents(self::FILE_PATH));
    }

    public function set(int $lastUpdateId)
    {
        $this->ensureFileExists();
        file_put_contents(self::FILE_PATH, $lastUpdateId);
        $this->value = $lastUpdateId;
    }

    public function get(): int
    {
        return $this->value;
    }

    public function isNewRequest(int $updateId): bool
    {
        return $updateId > $this->value;
    }

    private function ensureFileExists()
    {
        if (!file_exists(self::FILE_PATH)) {
            touch(self::FILE_PATH);
        }
    }
};

То, что делает класс, ясно: обработка последнего update_id через простой файл.

Примечание: курс старается быть как можно короче. Он не обеспечивает проверку ошибок. Используйте вместо этого свою собственную реализацию (например, используйте SplFileObject вместо file_{get|put}_contents() функций).

Теперь есть два метода получения обновлений: длинный опрос x или веб-перехватчики (проверьте Telegram bot API для подробнее о каждом методе и всех свойствах JSON). Приведенный выше код (или аналогичный) следует использовать в обоих случаях.

Примечание. В настоящее время невозможно использовать оба метода одновременно.

Метод длительного опроса (по умолчанию)

Таким образом, вы отправляете HTTPS-запросы в API ботов Telegram и получаете обновления в качестве ответа в объекте в формате JSON. Итак, для получения новых обновлений можно выполнить следующую работу (API, зачем использовать смещение ):

$botToken = "<token>";

$updates = json_decode(file_get_contents("https://api.telegram.org/bot{$botToken}/getUpdates?offset={$lastUpdateId->get()}"), true);

// Split updates from each other in $updates
// It is considered that one sample update is stored in $update

// See the section below
parseUpdate($update);

Метод WebHook (предпочтительно)

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

Первоначально вы должны включить WebHooks для своего бота, используя следующий запрос (подробнее) :

https://api.telegram.org/bot<token>/setWebhook?url=<file>

Замените <token> на свой токен бота, а <file> на адрес вашего файла, который будет принимать новые запросы. Опять же, это должен быть HTTPS.

Хорошо, последний шаг - создание вашего файла по указанному URL:

// The update is sent
$update = $_POST;

// See the section below
parseUpdate($update);

Отныне все запросы и обновления вашего бота будут напрямую отправляться в файл.

Реализация parseUpdate()

Его реализация полностью зависит от вас. Однако, чтобы показать, как использовать приведенный выше класс в реализации, это его образец и краткая реализация:

function parseUpdate($update)
{
    // Validate $update, first
    // Actually, you should have a validation class for it

    // Here, we suppose that: $update["update_id"] !== null
    if ($lastUpdateId->isNewRequest($update["update_id"])) {
        $lastUpdateId->set($update["update_id"]);
        // New request, go on
    } else {
        // Old request (or possible file error)
        // You may throw exceptions here
    }
}

Наслаждаться!

Изменить: спасибо @Amir за то, что он предложил версии, которые сделали этот ответ более полным и полезным.

person MAChitgarha    schedule 16.06.2017
comment
для webhook нельзя использовать offset и getUpdates. Я использовал ваш код без этого $updates, но проблема не исчезла ... - person Amir; 04.03.2020
comment
@Amir Да, в случае WebHooks запросы будут отправляться прямо в ваш файл; и поэтому вместо этого вам следует использовать $_REQUEST суперглобальный. - person MAChitgarha; 04.03.2020
comment
спасибо за внимание, не могли бы вы обновить свой ответ и добавить к нему поддержку случая веб-перехватчика? @MAChitgarha - person Amir; 05.03.2020
comment
@Amir Я только что отредактировал ответ; другими словами, я полностью переписал. Надеюсь, поможет. - person MAChitgarha; 05.03.2020
comment
существует проблема с поиском update_id внутри $_post, а он там не определен. Кстати, я был бы признателен, если бы вы прочитали мой последний вопрос, и если у вас есть какие-либо рекомендации по этому поводу, я был бы очень рад их услышать. и определенно большой палец вверх за этот ответ и ответ, который я получил бы в своем собственном вопросе :)) - person Amir; 05.03.2020
comment
@Amir Вообще-то, это должно сработать. Я давно не работал с WebHooks, так что, возможно, в моем ответе чего-то не хватает. Однако я думаю, ваша проблема в другом. Получаете ли вы обновления вообще (т.е. установлена ​​ли переменная $ _POST)? - person MAChitgarha; 06.03.2020
comment
да, я получаю обновления от file_get_contents('php://input'); - person Amir; 06.03.2020
comment
@Amir Нет, я имею в виду записать данные запроса в файл и проанализировать их. Как выглядит объект JSON? Вы должны получить действительный объект JSON API бота Telegram, иначе проблема в другом, AFAIK. - person MAChitgarha; 06.03.2020
comment
не было проблем с объектом JSON, и проблема заключалась в моем коде, что я неправильно передал update_id. Кстати, вы получите фатальную ошибку при запуске вашего файла, потому что в данный момент вы передаете NULL в isNewRequest(), но это нормально, когда запрос отправляется из телеграммы и у вас есть истинный update_id. пальцы вверх :)) - person Amir; 07.03.2020
comment
@Amir Спасибо за комментарии и внимание! Упоминание об этом, благодаря вам, я отредактировал свой ответ, чтобы он был более полезным. - person MAChitgarha; 07.03.2020

В режиме веб-перехватчика серверы Telegram отправляют обновления каждую минуту, пока не получит ответ «ОК» от программы веб-перехватчика. поэтому я рекомендую следующие шаги:

  1. Убедитесь, что ваша программа веб-перехватчика указала ее адрес в качестве параметра url метода setWebhook. Назовите его адрес в браузере. Он не производит вывод для просмотра, но убирает, что, вероятно, в вашей программе нет ошибки.
  2. Включите в вашу программу команду, которая выводит заголовок «200 OK Status», чтобы гарантировать, что программа отправит этот заголовок на сервер Telegram.
person Alireza Zojaji    schedule 07.03.2017
comment
вы можете предоставить несколько строк кода? Я пробовал то, что вы имели в виду, но получаю ответы ../ - person Bill Somen; 30.07.2020
comment
в php вы можете использовать header("HTTP/1.1 200 OK"); - person Alireza Zojaji; 31.07.2020

У меня такая же проблема, затем я попытался сбросить веб-перехватчик по умолчанию с помощью

https://api.telegram.org/bot[mybotuniqueIDvisible/setWebhook?url=

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

https://api.telegram.org/bot[mybotuniqueIDvisible/getUpdates

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

ПРИМЕЧАНИЕ: в моем случае он работал нормально, пока я не решил изменить / установить настройки бота конфиденциальности от botfather

person Willy Castro Alvarado    schedule 11.11.2015