尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

微信公众号后台开发实战:从零搭建Python Flask自动回复系统

微信公众号后台开发实战:从零搭建Python Flask自动回复系统 1. 从零到一一个公众号后台的诞生记如果你刚接手一个任务老板说“小王咱们搞个公众号吧要有菜单能点用户发消息能自动回复最好还能搞点小活动”而你之前只写过普通的网页对微信这套东西两眼一抹黑那这篇文章就是为你准备的。这不是一份官方文档的复读机而是一个踩过所有初级坑的过来人跟你聊聊怎么用最少的脑细胞把微信公众号后台从无到有跑起来。整个过程说白了就是申请账号、配置服务器、写代码处理微信的请求、再把代码部署到公网这四步。但每一步里都有官方文档不会明说、但能让你调试到凌晨三点的细节。我们今天的目标就是让你避开这些坑在喝下今晚第一杯咖啡前看到你的服务器成功响应微信发来的第一条验证消息。2. 战前准备账号、工具与核心概念扫盲在写第一行代码之前你得把“战场”布置好。这包括一个能用的公众号、一个本地开发环境以及理解几个关键概念不然你连微信在跟你聊什么都听不懂。2.1 公众号类型选择与基础配置首先你得有个公众号。去微信公众平台mp.weixin.qq.com注册。对于开发测试而言个人订阅号就完全够用了它几乎支持所有基础接口消息接收、自定义菜单等。如果你是企业需要微信支付、高级授权等能力才需要考虑服务号。注册过程就是填资料、扫码验证按提示走就行这里不赘述。注册成功后进入后台有几个关键配置需要立刻处理开发者ID(AppID/AppSecret)在“开发 - 基本配置”里。这是你公众号的唯一身份证和密码。AppID是公开的AppSecret是绝密的一旦泄露别人就能以你的公众号名义为所欲为。点击“重置”获取AppSecret并立即妥善保存比如用密码管理器页面上只会显示一次。服务器配置这是核心也是我们后续代码要对接的地方。在“开发 - 基本配置”页面下方。你需要准备一个公网可访问的URL比如https://yourdomain.com/wechat、一个任意的令牌(Token)、一个任意的消息加解密密钥(EncodingAESKey)。后两者你可以自己随便填一串字母数字比如Token填MyWeChatToken2024EncodingAESKey点击“随机生成”即可。这个配置现在先别提交因为我们服务器还没准备好。IP白名单如果你后续调用微信API的服务器有固定公网IP最好在这里配置上可以避免一些调用频率限制问题。2.2 本地开发环境搭建你的代码最终要跑在公网服务器上但开发和调试肯定在本地。你需要编程语言与环境微信后台开发不限制语言理论上任何能处理HTTP请求的语言都可以。但生态最成熟、资料最多的是Python和Node.js。本文将以PythonFlask框架为例因为它语法简洁适合快速原型开发。安装Python3.6以上版本。安装Flaskpip install flask内网穿透工具这是开发阶段最关键的一环。微信服务器只能回调公网URL但你本机localhost是内网。你需要一个工具将你本地http://localhost:5000的服务映射到一个公网域名上。常用的有ngrok简单易用免费版域名随机变化每次重启都会变。localtunnel类似ngrok。花生壳/神卓互联国内服务有时稳定性更好。微信开发者工具如果你开发的是小程序它自带内网穿透但纯公众号后端开发用起来不太直接。 我个人的习惯是使用ngrok启动命令ngrok http 5000它会给你一个https://xxxx.ngrok.io的地址这个就是你的临时公网URL。代码编辑器VS Code、PyCharm等按自己喜好来。2.3 理解微信的“对话”机制Token与签名在你和微信服务器开始“对话”前必须通过一次“握手”验证证明你确实是你声称的那台服务器。这个握手过程就依赖于上面提到的Token和一套签名算法。当你在公众号后台提交服务器配置时微信会向你填写的URL发送一个GET请求携带四个参数signature微信计算出的签名。timestamp时间戳。nonce随机数。echostr一个随机字符串。你的服务器需要做的是将你后台配置的Token、微信传来的timestamp、nonce三个参数按字典序排序后拼接成一个字符串。对这个字符串进行SHA1加密。将加密后的字符串与微信传来的signature进行比对。如果一致说明请求确实来自微信你就原样返回echostr参数验证即告成功。为什么这么做这确保了只有知道你预设Token的服务器即你才能通过验证防止任何人随便填个URL就冒充你的服务器。这个验证仅在首次配置时发生一次后续的消息推送是另一种验证方式。3. 核心实战搭建一个能“对话”的Flask后端理论说完我们开始写代码。目标是创建一个能通过微信验证、并能接收处理用户消息的简单后端。3.1 第一步通过校验成为微信的“好友”我们先处理最关键的服务器验证。创建一个文件比如叫wechat_server.py。from flask import Flask, request, abort import hashlib import time app Flask(__name__) # 这里填写你在公众号后台配置的Token WECHAT_TOKEN MyWeChatToken2024 app.route(/wechat, methods[GET, POST]) def wechat(): 处理微信服务器发送的所有请求验证和消息 # 1. GET请求处理 - 服务器验证 if request.method GET: signature request.args.get(signature, ) timestamp request.args.get(timestamp, ) nonce request.args.get(nonce, ) echostr request.args.get(echostr, ) # 校验签名 if check_signature(signature, timestamp, nonce): return echostr # 验证成功返回echostr else: abort(403) # 签名无效拒绝请求 # 2. POST请求处理 - 用户消息下一步实现 else: # 暂时先返回一个成功响应避免微信服务器重试 return success def check_signature(signature, timestamp, nonce): 校验微信服务器签名 # 1. 将token、timestamp、nonce三个参数进行字典序排序 temp_list sorted([WECHAT_TOKEN, timestamp, nonce]) # 2. 将三个参数字符串拼接成一个字符串 temp_str .join(temp_list) # 3. 进行sha1加密 sha1 hashlib.sha1() sha1.update(temp_str.encode(utf-8)) hashcode sha1.hexdigest() # 4. 将加密后的字符串与signature对比 return hashcode signature if __name__ __main__: app.run(host0.0.0.0, port5000, debugTrue)关键点解析app.route(/wechat)这个路由地址必须和你后续在公众号后台配置的URL路径一致。如果你配置的是https://xxx.com/wechat这里就是/wechat。check_signature函数严格按微信要求的步骤实现签名校验。排序要用sorted拼接后要编码(.encode(utf-8))再加密。abort(403)如果校验失败必须返回错误码微信服务器会记录配置失败。先运行python wechat_server.py启动本地服务。3.2 第二步配置公众号并完成“握手”启动你的内网穿透工具。例如运行ngrok http 5000假设你得到的地址是https://abcd1234.ngrok.io。进入公众号后台“服务器配置”页面。URL填写https://abcd1234.ngrok.io/wechat(注意加上你的路由/wechat)Token填写MyWeChatToken2024与代码中一致EncodingAESKey选择“随机生成”或手动填一个43位的字符串。消息加解密方式开发初期强烈选择“明文模式”。这样微信发来的消息是XML明文便于调试。等全部功能稳定后再切换到“安全模式”。点击“提交”。此时微信服务器会向你的URL发送一个GET请求进行验证。如果你的Flask应用运行正常且内网穿透成功你会看到后台提示“配置成功”。如果失败请按以下顺序排查检查本地服务浏览器访问http://localhost:5000/wechat?signaturexxxtimestampxxxnoncexxxechostrtest参数随便填看服务是否正常响应应该返回403。检查内网穿透用浏览器访问https://abcd1234.ngrok.io/wechat带参数看能否收到同样的403响应。如果不能说明穿透失败或路径错误。检查代码逻辑在check_signature函数中打印出计算的hashcode和微信传来的signature对比是否一致。常见错误是Token拼写错误、排序或拼接逻辑有误。检查网络确保服务器端口5000没有被防火墙阻止。注意ngrok的免费域名是动态的每次重启都会变。所以每次重启ngrok后都需要到公众号后台更新URL地址。这是开发测试阶段的常态生产环境你需要一个固定的域名和服务器。3.3 第三步接收与回复用户消息验证通过后用户向公众号发送消息微信会以POST请求的形式将消息内容推送到你的URL。消息体是XML格式。我们来完善上面的wechat函数处理POST请求并实现一个简单的文本消息回复。from flask import Flask, request, abort, make_response import hashlib import time import xml.etree.ElementTree as ET from xml.parsers.expat import ParserCreate # ... (之前的 check_signature 函数和 WECHAT_TOKEN 保持不变) ... def parse_xml(xml_str): 解析微信推送的XML消息 root ET.fromstring(xml_str) msg {} for child in root: msg[child.tag] child.text return msg def build_text_xml(to_user, from_user, content): 构造文本回复消息的XML xml_template xml ToUserName![CDATA[{ToUserName}]]/ToUserName FromUserName![CDATA[{FromUserName}]]/FromUserName CreateTime{CreateTime}/CreateTime MsgType![CDATA[text]]/MsgType Content![CDATA[{Content}]]/Content /xml return xml_template.format( ToUserNameto_user, FromUserNamefrom_user, CreateTimeint(time.time()), Contentcontent ) app.route(/wechat, methods[GET, POST]) def wechat(): if request.method GET: # ... (之前的GET验证代码不变) ... pass else: # POST 请求 - 处理用户消息 # 获取原始的XML数据 xml_str request.data.decode(utf-8) # 解析XML msg parse_xml(xml_str) msg_type msg.get(MsgType) from_user msg.get(FromUserName) # 发送者用户 to_user msg.get(ToUserName) # 接收者公众号 # 处理文本消息 if msg_type text: user_content msg.get(Content, ) reply_content f你发送的是{user_content}。我是自动回复机器人 # 构造回复XML。注意ToUserName和FromUserName要互换 reply_xml build_text_xml(from_user, to_user, reply_content) response make_response(reply_xml) response.content_type application/xml return response else: # 暂时忽略其他类型消息如图片、语音但必须返回success否则微信会重试 return success if __name__ __main__: app.run(host0.0.0.0, port5000, debugTrue)关键点解析与避坑指南XML解析微信消息是标准的XML。我们使用Python内置的xml.etree.ElementTree解析。注意消息字段都在CDATA块中ET会自动处理。字段互换这是最容易出错的地方接收消息时FromUserName是用户OpenIDToUserName是你的公众号原始ID。但当你回复消息时必须将这两个字段互换ToUserName填用户的OpenIDFromUserName填你的公众号原始ID。很多新手在这里搞反导致用户收不到回复。MsgType消息类型文本为text还有image图片、voice语音、event事件如关注、点击菜单等。你需要根据不同类型做相应处理。必须返回XML或‘success’如果你需要回复用户必须返回特定格式的XML如文本回复XML。如果你不想回复或处理了但无需回复也必须返回一个字符串successHTTP 200状态码。如果5秒内未响应或返回了其他内容/错误码微信服务器会认为推送失败并在接下来的30秒内重试3次这可能导致你的逻辑重复执行。调试技巧在开发阶段可以在关键位置如收到消息后、回复前打印日志到控制台或文件方便追踪流程。print(f”收到消息: {msg}”)。现在重启你的Flask服务并向你的公众号发送一条文本消息。你应该能收到自动回复。恭喜你一个最简单的微信公众号后台已经跑通了4. 功能进阶菜单管理与事件处理基础的收发消息搞定后公众号更常用的功能是自定义菜单和响应各种事件。4.1 创建自定义菜单菜单不是通过消息接口推送的而是需要你主动调用微信的创建菜单API。这需要用到你的AppID和AppSecret。首先写一个函数获取access_token。这是调用几乎所有微信高级接口的“门票”有效期2小时需要全局缓存。import requests import json APPID 你的AppID APPSECRET 你的AppSecret ACCESS_TOKEN None TOKEN_EXPIRE_TIME 0 def get_access_token(): 获取并缓存access_token global ACCESS_TOKEN, TOKEN_EXPIRE_TIME current_time time.time() # 如果token未过期直接返回缓存的 if ACCESS_TOKEN and current_time TOKEN_EXPIRE_TIME: return ACCESS_TOKEN url fhttps://api.weixin.qq.com/cgi-bin/token?grant_typeclient_credentialappid{APPID}secret{APPSECRET} try: resp requests.get(url, timeout5).json() if access_token in resp: ACCESS_TOKEN resp[access_token] TOKEN_EXPIRE_TIME current_time resp[expires_in] - 300 # 提前300秒过期留出缓冲 print(f”获取新token: {ACCESS_TOKEN}“) return ACCESS_TOKEN else: print(f”获取token失败: {resp}“) return None except Exception as e: print(f”请求token异常: {e}“) return None然后调用创建菜单接口。def create_menu(): 创建自定义菜单 access_token get_access_token() if not access_token: return False menu_data { button: [ { type: click, name: 今日推荐, key: V1001_TODAY_MUSIC }, { name: 更多, sub_button: [ { type: view, name: 搜索, url: https://www.baidu.com/ }, { type: miniprogram, name: 小程序, url: http://mp.weixin.qq.com, appid: 小程序的appid, pagepath: pages/index/index } ] } ] } url fhttps://api.weixin.qq.com/cgi-bin/menu/create?access_token{access_token} # 注意微信要求JSON数据必须是UTF-8编码且不能有BOM头。Flask的jsonify或requests的json参数会自动处理。 resp requests.post(url, jsonmenu_data, timeout5).json() if resp.get(errcode) 0: print(“菜单创建成功”) return True else: print(f”菜单创建失败: {resp}“) return False # 可以在某个管理后台触发或直接脚本执行 if __name__ __main__: create_menu()实操心得access_token务必缓存。频繁获取会触发频率限制且AppSecret频繁暴露也不安全。菜单结构是个嵌套的JSON。type可以是click点击事件、view跳转网页、miniprogram打开小程序等。创建是覆盖操作新菜单会完全替换旧菜单。菜单审核个人订阅号的菜单可能不会立即显示或者需要一定时间同步这是正常现象。4.2 处理菜单点击事件用户点击了type为click的菜单后微信服务器会向你的后台推送一个事件消息MsgType为eventEvent为CLICK并通过EventKey字段告诉你点击了哪个菜单。我们需要扩展之前的消息处理逻辑app.route(/wechat, methods[GET, POST]) def wechat(): # ... GET部分省略 ... else: # POST xml_str request.data.decode(utf-8) msg parse_xml(xml_str) msg_type msg.get(MsgType) from_user msg.get(FromUserName) to_user msg.get(ToUserName) # 处理事件消息 if msg_type event: event_type msg.get(Event) if event_type CLICK: event_key msg.get(EventKey) if event_key V1001_TODAY_MUSIC: reply_content “点击了「今日推荐」菜单” else: reply_content “收到了未知的点击事件。” reply_xml build_text_xml(from_user, to_user, reply_content) response make_response(reply_xml) response.content_type application/xml return response elif event_type subscribe: # 处理关注事件 reply_content “感谢关注发送「帮助」查看功能。” reply_xml build_text_xml(from_user, to_user, reply_content) response make_response(reply_xml) response.content_type application/xml return response # 可以继续处理其他事件如 unsubscribe取消关注、VIEW点击view菜单等 else: return success # 处理文本消息之前的逻辑 elif msg_type text: # ... 之前文本处理逻辑 ... pass else: return success这样当用户点击“今日推荐”菜单时就会收到对应的回复。事件处理让公众号从被动应答变成了可以主动交互。5. 部署上线与生产环境考量本地调试通过后你需要一个真正的、稳定的公网服务器来托管你的代码。5.1 服务器与域名准备购买云服务器腾讯云、阿里云等选择最低配置的Linux如CentOS 7/8, Ubuntu即可成本每月几十元。配置域名购买一个域名并在云服务商控制台将域名解析到你的服务器公网IP。申请SSL证书微信要求服务器地址必须是HTTPS。你可以使用Let‘s Encrypt免费证书。云厂商通常也提供免费的单域名证书。配置Web服务器生产环境不建议直接用Flask自带的开发服务器。使用NginxGunicorn是Python Web应用的经典组合。Nginx处理静态文件、反向代理、SSL卸载。Gunicorn一个Python WSGI HTTP服务器负责运行你的Flask应用。5.2 使用Gunicorn启动应用在服务器上安装依赖后使用Gunicorn启动应用# 安装gunicorn pip install gunicorn # 在项目根目录下启动-w 指定worker数量-b 绑定地址和端口 gunicorn -w 4 -b 127.0.0.1:8000 wechat_server:app这里应用跑在127.0.0.1:8000对外不可见。5.3 配置Nginx反向代理与HTTPS编辑Nginx配置文件如/etc/nginx/conf.d/wechat.confserver { listen 80; server_name yourdomain.com; # 你的域名 # 将HTTP请求重定向到HTTPS return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name yourdomain.com; # SSL证书路径 ssl_certificate /path/to/your/fullchain.pem; ssl_certificate_key /path/to/your/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; location / { proxy_pass http://127.0.0.1:8000; # 转发给Gunicorn proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /wechat { # 微信服务器可能会用特定的User-Agent一般无需特殊处理但确保能访问到 proxy_pass http://127.0.0.1:8000/wechat; # 保持和上面一样的proxy_set_header proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }配置完成后重载Nginxsudo nginx -s reload。5.4 更新公众号配置与最终测试将公众号后台的服务器配置URL更新为你的生产环境地址https://yourdomain.com/wechat。Token和EncodingAESKey保持不变。点击提交验证。此时验证请求会经过微信服务器 - 你的域名 - Nginx - Gunicorn - Flask应用。验证通过即表示部署成功。进行完整的端到端测试关注公众号、发送消息、点击菜单确保所有功能正常。生产环境注意事项日志配置完善的日志记录如Python的logging模块记录所有请求和错误方便排查问题。进程管理使用systemd或Supervisor来管理Gunicorn进程实现开机自启和崩溃重启。Token管理AppSecret等敏感信息不要硬编码在代码中。使用环境变量或配置文件并在服务器上设置。消息排重微信的消息可能因网络问题重推。如果你的逻辑不是幂等的比如点击一次菜单增加一次积分需要根据消息ID(MsgId)进行排重处理。性能对于简单的自动回复单机性能足够。如果涉及复杂业务如数据库查询、调用外部API需注意响应时间微信服务器等待回复的超时时间是5秒。走到这一步你已经拥有了一个可以稳定运行、具备基本交互能力的微信公众号后台。从本地调试到公网部署这套流程覆盖了从开发到上线的核心环节。后续无论是接入数据库实现用户管理还是接入AI接口实现智能对话都是在这个坚实的基础上进行的功能叠加。
返回列表