个人微信API结果处理:4步解决状态码与业务数据 前阵子接了个需求给客户做消息推送调用的就是微信那边的接口。当时赶进度看HTTP状态码是200就直接当成功处理了日志也没记细。结果上线第三天客户反馈说有几条消息没收到但我后端日志里全是发送成功。排查了半天才发现HTTP是200没错但返回体里的业务code是个非0值意思是消息压根没真正发出去。我那会儿压根没解析返回体只看了个壳。这坑踩得有点低级但据我观察新手基本都踩过没踩过的多半是还没碰到。今天就把返回结果的处理流程梳理一遍给自己也留个笔记顺便分享给同样在搞微信API对接的同学少踩一个是一个。返回结果到底长啥样先看下大部分接口的返回结构绝大多数都遵循这个套路{ code: 0, msg: success, data: { msgId: xxx, sendTime: 1697000000 } }外层就三个字段code是业务码msg是描述data是真正的业务数据。看起来很简单但坑就坑在很多人只看了HTTP状态码就放过了根本没往下扒一层。我自己对接个人微信API的时候文档里其实写得很清楚但当时图省事直接看200就return了结果就翻车了。下面这4步是我后来总结的处理流程按顺序走基本不会漏。第一步看HTTP状态码这是最外层的一层判断。HTTP状态码反映的是通信层面的成败跟业务没关系。200通信成功请求到达服务器了服务器也给了响应4xx请求有问题比如参数不对、鉴权失败、URL写错了5xx服务器那边出问题了比如内部异常、超载、宕机很多人就在这一步停下来了看到200就return true结果业务失败的情况全被漏掉。HTTP 200只能说明信送到了不能说明事情办成了这俩完全是两码事。另外4xx和5xx的处理策略也不一样4xx是自己的问题重试也没用得改代码5xx是对方的问题可以重试。第二步看业务code这才是关键中的关键。code字段是业务层面的成败标志不同接口可能有不同的码值约定但通用规则是0成功非0失败具体含义对照开发文档查我那次踩坑就是因为没看这个字段。后来整理了几个常见的code方便对照1001参数缺失1002鉴权失败token过期或者key错了2001消息内容违规被审核拦了3001发送频率超限5000服务内部错误每个码对应的处理策略不一样比如1001要修参数3001要做重试加退避5000可能是临时故障可以重试。重试策略也得区分不是所有失败都重试。第三步看msg字段msg是给人看的不是给程序看的。它的作用主要是写到日志里方便排查异常时直接抛给上层前端能显示定位问题时第一眼就能看到原因千万别拿msg做程序判断因为msg文案可能会变code才是稳定的。我见过有人拿msg.includes(成功)判断成功结果人家文案改了个字整个逻辑就崩了找了好久才发现。msg的价值在于日志我现在的习惯是每次调用都把code和msg一起打日志哪怕成功了也打出问题回头一搜就能定位到具体哪次调用。第四步看data字段data是业务数据这里有几个容易翻车的点新手特别要注意类型不确定有的接口data是对象有的是数组有的失败时直接是null可能为空成功但没数据的情况是存在的比如查询接口查不到结果字段不固定不同code下data结构可能不一样失败时data经常是空对象处理data之前一定要判空并且按文档约定做类型校验。我现在的习惯是拿到data先print一下类型确认结构再写解析逻辑。还有个坑是data里某些字段可能缺失用.get()而不是直接取能少很多KeyError。状态码组合和处理策略把HTTP状态码和业务code组合起来看基本能覆盖所有情况。下面这张表是我自己整理的贴在工位上每天看HTTP状态码业务code含义处理策略2000完全成功正常处理data记日志200非0通信成功但业务失败记录code和msg按code分类处理4xx-请求有问题修参数或鉴权不重试5xx-服务端问题重试加退避策略超时-网络问题重试告警这张表建议新人来了先看一遍能少走不少弯路。我自己写代码的时候基本就是按这个表走省心很多代码里也不会到处塞乱七八糟的if判断。处理函数的写法分享下我现在用的工具函数把上面的逻辑封装一下调用方就清爽了class BizError(Exception): def __init__(self, code, msg): self.code code self.msg msg super().__init__(f[{code}] {msg}) def parse_response(resp): if resp.status_code 500: raise BizError(resp.status_code, 服务端异常建议重试) if resp.status_code 400: raise BizError(resp.status_code, 请求异常: resp.text[:200]) body resp.json() code body.get(code, -1) msg body.get(msg, ) if code ! 0: raise BizError(code, msg) return body.get(data)调用方就一行data parse_response(resp)失败抛异常全局捕获统一处理。这样业务代码里就不会到处塞if判断了干净很多新人接手也容易看懂。别只盯着HTTP状态码回到开头那个坑本质上就是把通信成功等同于业务成功了。这俩是完全不同的两件事HTTP只管信使code才管结果。我后来给团队立了个规矩所有外部接口调用必须解析业务code日志必须打印完整返回体发现非0的code必须告警。规则定下来之后类似的事故基本没再发生。对接Eyun平台这种第三方服务的时候更要养成这个习惯因为接口是别人提供的你没法保证它每次都按预期返回唯一能做的就是认真解析每一个字段把不确定性挡在自己的代码里。写到这里差不多就这些了。返回结果处理看着是个小事但出问题的时候基本全是大事客户那边收不到消息损失的都是真金白银。希望这篇能帮到还在踩坑的同学别再像我当年那样只看200就放过把code字段当成第一公民来对待比啥都强。Eyun平台开发文档