5

私は Telegram ボットを作成しており、公式のボット APIを使用しています。リクエストを処理し、すべてのリクエストに対してレスポンスを送信する Webhook サーバーがあります200 OK

サーバーが停止する前に Webhook が切り離されるため、Telegram はそれ以上更新を送信しません。ただし、ボットをオンにして webhook URL を再度設定すると、Telegram は古い更新で webhook サーバーをフラッディングし始めます。

/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);

前もって感謝します。

4

4 に答える 4

3

最善の方法は、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()

現在、更新を取得する方法は 2 つあります。Long Polling xor WebHooks (各方法とすべての JSON プロパティの詳細については、Telegram ボット APIを確認してください)。上記のコード (または類似のコード) は、どちらの場合にも使用する必要があります。

: 現在、両方の方法を同時に使用することはできません。

ロング ポーリング方式 (デフォルト)

このようにして、HTTPS 要求を Telegram ボット API に送信すると、JSON 形式のオブジェクトで応答として更新を取得できます。したがって、新しい更新を取得するために次の作業を行うことができます ( APIなぜ offset を使用するのか):

$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 である必要があります。

OK、最後のステップは、指定された 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に感謝します。

于 2017-06-16T21:22:42.857 に答える