个人申请的订阅号,未认证,可用功能可在 微信公众号平台 - 接口权限 处查看
使用代码开发,首先需要在 基础配置-服务器配置 中进行设置
填写服务器地址(URL)、Token和EncodingAESKey,其中 URL 是用来接收微信消息和事件的接口URL。Token可以任意填写,用作生成签名(该 Token 会和接口 URL 中包含的 Token 进行比对,从而验证安全性)。EncodingAESKey手动填写或随机生成,将用作消息体加解密密钥在点击【提交】按钮后,微信会向填写的服务器地址发送一个GET请求,携带signature、timestamp、nonce、echostr四个参数
微信开发文档上给的加密规则:
1)将token、timestamp、nonce三个参数进行字典序排序
2)将三个参数字符串拼接成一个字符串进行sha1加密
3)开发者获得加密后的字符串可与 signature 对比,标识该请求来源于微信
def sign_sha1(signature, timestamp, nonce): """ 服务器配置 验证 :param signature: :param timestamp: :param nonce: :return: """ temp = [TOKEN, timestamp, nonce] temp.sort() hashcode = hashlib.sha1("".join(temp).encode('utf-8')).hexdigest() logger.info(f"加密:{hashcode},微信返回:{signature}") if hashcode == signature: return True # 返回的 echostr 需要是整型。int(echostr)
fastapi接收接口
# main.py from fastapi import FastAPI from api import wechat app = FastAPI(title="EasyTest接口项目", description="这是一个接口文档", version="1.0.0", docs_url=None, redoc_url=None) app.include_router( wechat.router, prefix="/wx", tags=["wx"], responses=response_error ) # wechat.py from fastapi import APIRouter from public.wx_public import sign_sha1 router = APIRouter() @router.get("/", summary="微信服务器配置验证") async def handle_wx(signature, timestamp, nonce, echostr): try: if sign_sha1(signature, timestamp, nonce): return int(echostr) else: logger.error("加密字符串 不等于 微信返回字符串,验证失败!!!") return "验证失败!" except Exception as error: return f"微信服务器配置验证出现异常:{error}"
关注/取消事件和被动回复用户消息
用户在关注与取消关注公众号时,微信会发送一个POST请求,携带xml数据包,把这个事件推送给服务器地址
fastapi接收接口
import aiohttp from starlette.responses import HTMLResponse, Response # parse_xml, Message 参考地址:https://github.com/vastsa/Wechat-Fastapi from public.wx_message import parse_xml, Message from public.wx_public import sign_sha1, send_wx_msg @router.post("/", summary="回复微信消息") async def wx_msg(request: Request, signature, timestamp, nonce, openid): if sign_sha1(signature, timestamp, nonce): try: async with aiohttp.ClientSession() as session: async with session.get("http://121.41.54.234/wx/login") as resp: res = await resp.json() token = res["result"]["access_token"] except Exception as error: logger.error(f"获取微信登录token出现异常:{error}") token = "" try: rec_msg = parse_xml(await request.body()) to_user = rec_msg.FromUserName from_user = rec_msg.ToUserName content, media_id = send_wx_msg(rec_msg, token) if rec_msg.MsgType == 'text' and not media_id: return Response( Message(to_user, from_user, content=content).send(), media_type="application/xml") elif rec_msg.MsgType == 'event' and content: return Response( Message(to_user, from_user, content=content).send(), media_type="application/xml") elif rec_msg.MsgType == "image" or media_id: return Response( Message(to_user, from_user, media_id=media_id, msg_type="image").send(), media_type="application/xml") except Exception as error: logger.error(f"微信回复信息报错:{error}") return HTMLResponse('success') # wx_public.py def send_wx_msg(rec_msg, token): content, media_id = "", "" if rec_msg.MsgType == 'text': logger.info(f"文本信息:{rec_msg.Content}") patt = r"[\d+]{4}.[\d+]{1,2}.[\d+]{1,2}" content = re.findall(patt, rec_msg.Content) if content: # 输入出生年月日,回复信息 content = age_content(content) else: content = rec_msg.Content if content in ["图片", "小七"] and token: # 输入 "图片", "小七" 回复图片 media_id = wx_media(token) elif content in ["今天", "today"]: # 输入 "今天", "today" 回复信息 content = fishing(make=True) elif content == "放假": # 输入 "放假" 回复信息 content = fishing() else: # 输入 股票名称、股票代码 回复信息 content = shares(stock_code=rec_msg.Content) if not content: # 根据输入值返回 content = rec_msg.Content elif rec_msg.MsgType == 'event': if rec_msg.Event == "subscribe": # 关注公众号回复信息 content = FOLLOW elif rec_msg.Event == "unsubscribe": # 取消关注 logger.info(f"用户 {rec_msg.FromUserName} 取消关注了!!!") elif rec_msg.MsgType == "image": # 收到图片返回 if token: media_id = wx_media(token) else: media_id = rec_msg.MediaId return content, media_id
log日志打印信息
公众号效果
标签:media,FastApi,content,公众,微信,msg,rec,wx From: https://www.cnblogs.com/changqing8023/p/16817207.html