首页 > 解决方案 > Python Flask 服务器出现“代码 400”错误(从 Telegram-webhook 发送的 POST 请求)

问题描述

语境

我目前正在关注本教程。- Telegram Bot 与 Python 教程 #3:创建 Bot 和 Webhook | 项目


第一步

我已经使用以下 python 代码设置了一个 Flask 服务器:

from flask import Flask
from flask import request
from flask import Response
import json

app = Flask(__name__)


@app.route('/', methods=['POST', 'GET'])
def index():
    if request.method == 'POST':

        print(request)

        message = request.json()

        with open('telegram_request.json', 'w', encoding='utf-8') as filename:
            json.dump(message, filename, ensure_ascii=False, indent=4)

        # prevents telegram from spamming
        return Response('Ok', status=200)
    else:
        return """
            <h1> Flask Server </h1>
            <h2> Up and running </h2>
        """


if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=8443)


第二步

我在路由器中端口转发端口8443以使服务器对外界可见(教程中的隧道步骤)。

域名“ myprivatedomain.com:8443 ”现在重定向/引用已设置的烧瓶服务器。


第三步

我正确设置了Telegram-API webhook,从 Telegram 获得以下响应代码:

{"ok":true,"result":true,"description":"Webhook 已设置"}


现在

Telegram 聊天中发送消息之前:没有错误

聊天中发送消息后,弹出以下错误:

代码 400,消息错误 HTTP/0.9 请求类型('RANDOM BYTE V​​ALUES like \x00\x03')

代码 400,消息错误请求语法('RANDOM BYTE V​​ALUES like \x00\x03')

代码 400,消息错误请求版本('RANDOM BYTE V​​ALUES like \x00\x03')


我想要的是

根据教程,您可以在 Telegram 发出 POST 请求时编写一个 .json 文件(参见示例:here)。我想保存 Telegram webhook 提供的消息对象(如教程视频中所示)。使用 webhook 获取更新比不断查询 getUpdates() 方法要好;该方法也返回旧消息。


我试过的

我试图添加:

ssl_context='adhoc'

app.run(debug=True, host='0.0.0.0', port=8443)

使连接HTTPS。

使用此 ssl_context 时,也无法加载主页..


优选输出

当用户在 Telegram 聊天中发送消息时 --> Python 保存消息对象的 .json 文件。

标签: pythonflaskbad-request

解决方案


您需要启用 SSL 才能正常工作。Telegram 正在尝试与您的服务器启动 SSL 会话,但您没有启用 SSL,因此您看到了错误的请求。

ssl_context='adhoc'可能适用于测试应用程序,但我也有一种预感,电报需要有效的SSL 证书,而不仅仅是临时(或自签名)证书。请注意视频中 URL 左侧的锁,并且缺少安全警告,该警告将与无效或自签名证书一起出现。

为确保 SSL 正常工作,设置ssl_contextadhoc,启动应用程序,然后浏览至https://myprivatedomain.com:8443/index. 如果你可以浏览到它,那么 Telegram 也可以在获得有效证书后浏览到它,当然。

接下来,要获得有效(且免费)的 SSL 证书,您可以使用LetsEncrypt

拥有有效的 SSL 证书和密钥文件后,您可以将ssl_context参数传递app.run给证书文件的路径和密钥文件的路径的元组("/path/to/fullchain.pem", "/path/to/privkey.pem")

您的完整运行功能应如下所示

app.run(debug=True, host='0.0.0.0', port=8443, ssl_context=("/path/to/fullchain.pem", "/path/to/privkey.pem"))

或者,您可以使用 Apache 或 Nginx 使用 SSL 保护您的网站,并反向代理您的机器人。这些选项通常会在最终产品中使用,所以我理解你现在是否不想与它们一起进入杂草,但无论如何这是一个好习惯。

希望这会有所帮助。


推荐阅读