跳到主要内容
QQ 机器人 Webhook 方式简易部署教程 | 极客日志
Python AI
QQ 机器人 Webhook 方式简易部署教程 综述由AI生成 针对 QQ 开放平台对 AIGC 接口的限制及 WebSocket 服务废弃的情况,介绍利用官方开源 Python 代码通过 Webhook 方式部署 QQ 机器人的完整流程。内容包括在 QQ 开放平台完成账号注册、沙箱配置、开发管理及回调地址设置;在服务器上创建 Python 虚拟环境并安装 FastAPI、Uvicorn 等依赖;配置 Apache 反向代理及 Systemd 服务以启动 Webhook 进程;最后通过 Curl 命令验证服务状态并运行机器人主程序。此外,还补充了私聊消息处理(C2C_MESSAGE_CREATE)等扩展功能的代码实现细节,帮助开发者快速搭建可用的机器人服务。
Elasticer 发布于 2026/3/25 更新于 2026/6/7 30 浏览QQ 机器人 Webhook 方式简易部署教程
官方最近对使用 AIGC 接口的机器人进行了封禁,且以往的 WebSocket 服务将陆续不再支持,故本文旨在以最为基础的办法,不使用外部框架,利用 Webhook 方式接入机器人。
准备工作
前往 QQ 开放平台 注册机器人账号。
沙箱配置
在**'沙箱配置'**中配置用于机器人测试的群聊、私聊账号以及频道信息。
开发管理
在**'开发管理'中可以看到 机器人的 ID、密钥**等信息,很重要,后续需要使用。IP 白名单中需要放行你的服务器公网 IP。
回调配置
在**'回调配置'**中需要配置 Webhook 服务使用的回调地址,需要准备一个已备案的域名,并且域名需要解析到你的公网 IP 上。同时,域名需要部署 SSL 证书(能用 https 访问)。
建议配置如下后缀,后续配置 Webhook 时需要使用:
你的域名/qqbot-webhook/callback
填写好此时会提示'校验失败',不用着急,因为 Webhook 服务还没有启用,过一会儿会回来重填。
添加事件建议全选,也可以自选需要的,选好后需要在右下角确认配置。
阿里云的免费 SSL 个人测试证书不含 CA,回调地址验证时会失败,建议使用其他免费 SSL 证书。
代码部署
本文疏于解释的地方可参考 官方文档 和 。
创建 python 环境 在自己的服务器上合适的位置(本文使用/opt/qqbot)创建用于管理机器人代码的文件夹,并从代码仓库导入文件。
git clone https://github.com/Space-ash/QQbot.git
端口放行 阅读 官方 API 文档 中'事件订阅与通知'一节,回调地址允许配置的端口号为:80、443、8080、8443,因此需要在服务器对应的端口配置回调代码。
端口 描述 类型 6195 企业微信默认端口 可选 6199 QQ 个人号 (aiocqhttp) 默认端口 可选 6196 QQ 官方接口 (Webhook) 默认端口 需要
本例使用 Apache,如果你需要使用 Nginx 或 Caddy 等,可以自行查阅相关资料。
找到解析到服务器的域名对应的 Apache 配置文件,文件名通常为"你的域名.conf"。
<VirtualHost *:80>
# ... 此处是默认有的一大段代码,不用管 ...
# 只用插入这一段,反代 Webhook 回调
ProxyPass "/qqbot-webhook/callback" "http://127.0.0.1:6196/qqbot-webhook/callback"
ProxyPassReverse "/qqbot-webhook/callback" "http://127.0.0.1:6196/qqbot-webhook/callback"
</VirtualHost>
<VirtualHost *:443>
# ... 此处是默认有的一大段代码,不用管 ...
# 只用插入这一段,反代回调,需要在相应的地方改为你的回调地址后缀
ProxyPass "/qqbot-webhook/callback" "http://127.0.0.1:6196/qqbot-webhook/callback"
ProxyPassReverse "/qqbot-webhook/callback" "http://127.0.0.1:6196/qqbot-webhook/callback"
# 如果以后用 WS,把升级头转过去
RewriteEngine On
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteRule ^/qqbot-webhook/(.*) ws://127.0.0.1:6196/qqbot-webhook/$1 [P,L]
</VirtualHost>
qqbot_webhook.py 使用 Webhook 服务的主要文件,打开后你需要填入'开发管理'中查看到的机器人 ID 和密钥。
APP_ID = "your_app_id_here"
BOT_SECRET = "your_bot_secret_here"
如果需要保存日志,则将此处的 LOG_DIR 改为你的地址。
LOG_DIR = "/opt/qqbot/logs"
os.makedirs(LOG_DIR, exist_ok=True )
def write_log (level: str , msg: str ):
"""单文件临时日志,全部写到 qqbot_webhook.log"""
path = os.path.join(LOG_DIR, "qqbot_webhook.log" )
line = f"{datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S' )} | {level} | {msg} \n"
with open (path, "a+" , encoding="utf-8" ) as f:
f.write(line)
f.flush()
回调地址后缀"/qqbot-webhook/callback"则需要改为你希望填写在'回调配置'中的地址后缀。
@app.post("/qqbot-webhook/callback" )
async def qqbot_callback (request: Request ):
write_log("INFO" , "=== 收到 Webhook 请求 ===" )
raw = await request.body()
qqbot_webhook.service Service 文件用于后台运行 Webhook 服务,需要将 WorkingDirectory 改为你的 service 地址,ExecStart 改为你的 uvicorn 地址。
[Unit]
Description =QQ Bot Webhook (FastAPI)
After =network.target
[Service]
User =www-data
WorkingDirectory =/opt/qqbot
ExecStart =/opt/qqbot/.venv/bin/uvicorn qqbot_webhook:app --host 127.0 .0.1 --port 6196
Restart =always
RestartSec =3
[Install]
WantedBy =multi-user.target
启用 Webhook 服务 把你的项目路径下的 service 单元链接进系统搜索路径。
sudo systemctl link /opt/qqbot/qqbot_webhook.service
sudo systemctl daemon-reload
sudo systemctl enable --now qqbot_webhook
sudo systemctl restart qqbot_webhook
sudo systemctl status qqbot_webhook
验证服务状态 curl -v -i http://127.0.0.1:6196/qqbot-webhook/callback \
-H 'Content-Type: application/json' \
-d '{"op":13,"d":{"plain_token":"Arq0D5UvOp","event_ts":"1741"}}'
如果终端返回 200 OK 以及一个含有"plain_token"和"signature"的 json,则说明服务启用成功了。
* Trying 127.0 .0 .1 :6196...
* Connected to 127.0 .0 .1 (127.0.0.1) port 6196
> POST /qqbot-webhook/callback HTTP/1.1
> Host: 127.0 .0 .1 :6196
> User-Agent: curl/8.5.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 76
< HTTP/1.1 200 OK
< date: Tue, 21 Oct 2025 13:37:25 GMT
< server: uvicorn
< content-length: 181
< content-type: application/json
< * Connection
{"plain_token" :"Arq0D5UvOp" ,"signature" :"d7d2e0...83d605" }
journalctl -u qqbot_webhook -n 100 -f
成功后回到官方的'回调配置'网页,在请求地址中填入你的回调地址,发现不再提示校验失败。
你的域名/qqbot-webhook/callback
保存配置后,在终端进入项目的 python 虚拟环境,并运行机器人。
source .venv/bin/activate
python3 ./yourbot/demo_yourbot.py
[INFO] (client.py :162 )_bot_login [botpy] 登录机器人账号中...
[INFO] (robot.py :65 )update_access_token [botpy] access_token expires_in 2964
[INFO] (client.py :181 )_bot_init [botpy] 程序启动...
[INFO] (connection.py :60 )multi_run [botpy] 最大并发连接数:1 , 启动会话数:1
[INFO] (client.py :242 )bot_connect [botpy] 会话启动中...
[INFO] (gateway.py :115 )ws_connect [botpy] 启动中...
[INFO] (gateway.py :142 )ws_identify [botpy] 鉴权中...
[INFO] (gateway.py :85 )on_message [botpy] 机器人「说怪话 - 测试中」启动成功!
[INFO] (gateway.py :223 )_send_heart [botpy] 心跳维持启动...
[INFO] (demo_chimera.py :17 )on_ready robot 「说怪话 - 测试中」on_ready !
如果机器人没有回复,可以查看 logs/qqbot_webhook.log 中的信息,或者利用 journalctl -u qqbot_webhook -n 100 -f 查看终端的运行日志进行调试。
功能扩展示例
发送私聊消息 C2C_MESSAGE_CREATE
import botpy
from botpy.http import BotHttp
from botpy.api import BotAPI
from botpy.message import C2CMessage
from botpy.types.gateway import MessagePayload
from yourbot.demo_yourbot import MyClient
def build_message_payload (event: dict ) -> MessagePayload:
return {
"author" : event.get("author" , {}),
"channel_id" : event.get("channel_id" , "" ),
"content" : event.get("content" , "" ),
"guild_id" : event.get("guild_id" , "" ),
"id" : event.get("id" , "" ),
"member" : event.get("member" , {}),
"message_reference" : event.get("message_reference" , {}),
"mentions" : event.get("mentions" , []),
"attachments" : event.get("attachments" , []),
"seq" : event.get("seq" , 0 ),
"seq_in_channel" : event.get("seq_in_channel" , "" ),
"timestamp" : event.get("timestamp" , "" ),
}
if op == 0 :
event = payload.get("d" , {})
event_type = payload.get("t" , "" )
if event_type == "C2C_MESSAGE_CREATE" :
write_log("INFO" , "=== C2C_MESSAGE_CREATE 事件 ===" )
http = BotHttp(timeout=5 , app_id=APP_ID, secret=BOT_SECRET)
api = BotAPI(http)
event_id = event.get("id" , "" )
payload = build_message_payload(event)
message = C2CMessage(api, event_id, payload)
intents = botpy.Intents(public_messages=True )
client = MyClient(intents=intents)
await client.on_c2c_message_create(message)
import botpy
from botpy import logging
from botpy.ext.cog_yaml import read
from botpy.message import C2CMessage
test_config = read(os.path.join(os.path.dirname(__file__), "config.yaml" ))
_log = logging.get_logger()
class MyClient (botpy.Client):
async def on_ready (self ):
_log.info(f"robot「{self.robot.name} 」on_ready!" )
async def on_c2c_message_create (self, message: C2CMessage ):
_log.info(f"收到消息:{message.content} 来自 {message.author.user_openid} " )
await message._api.post_c2c_message(
openid=message.author.user_openid,
msg_type=0 ,
msg_id=message.id ,
content=f"我收到了你的消息:{message.content} "
)
class C2CMessage (BaseMessage ):
__slots__ = ("author" ,)
def __init__ (self, api: BotAPI, event_id, data: gateway.MessagePayload ):
super ().__init__(api, event_id, data)
self .author = self ._User(data.get("author" , {}))
def __repr__ (self ):
slots = self .__slots__ + super ().__slots__
return str ({items: str (getattr (self , items)) for items in slots if not items.startswith("_" )})
class _User :
def __init__ (self, data ):
self .user_openid = data.get("user_openid" , None )
def __repr__ (self ):
return str (self .__dict__)
async def reply (self, **kwargs ):
return await self ._api.post_c2c_message(openid=self .author.user_openid, msg_id=self .id , **kwargs)
class BotAPI :
""" 机器人相关的 API 接口类
使用注意:
- 如果要直接使用 api,可以通过 client 的内部成员变量,通过`self.api.xx`来使用
- 设置超时时间:Client(timeout=5)
- API 当前返回的所有自定义类型数据为字典数据,通过 TypedDict 进行类型提示
"""
def __init__ (self, http: BotHttp ):
""" Args: http (BotHttp): 用于发送请求的 http 客户端。 """
self ._http = http
class BotHttp :
""" TODO 增加请求重试功能 @veehou TODO 增加并发请求的锁控制 @veehou """
def __init__ (self, timeout: int , is_sandbox: bool = False , app_id: str = None , secret: str = None , ):
self .timeout = timeout
self .is_sandbox = is_sandbox
self ._token: Optional [Token] = None
if not app_id else Token(app_id=app_id, secret=secret)
self ._session: Optional [aiohttp.ClientSession] = None
self ._global_over: Optional [asyncio.Event] = None
self ._headers: Optional [dict ] = None
class MessagePayload (TypedDict ):
author: UserPayload
channel_id: str
content: str
guild_id: str
id : str
member: Member
message_reference: MessageRefPayload
mentions: List [UserPayload]
attachments: List [MessageAttachPayload]
seq: int
seq_in_channel: str
timestamp: str
相关免费在线工具 RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
Mermaid 预览与可视化编辑 基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
随机西班牙地址生成器 随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online
curl 转代码 解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online