webhook的核心是主动权归属——发送方为调用者,接收方为服务端,二者协议一致但角色不可互换;c#中无专用sdk,需依托asp.net core minimal api或controller规范处理post请求、校验签名并返回json响应,同时httpclient须复用、序列化须utf8、消息结构须严格符合平台字段要求。

WebHook 的核心不是“怎么接”或“怎么发”,而是「谁控制主动权」——发送方是调用者,接收方是服务端;两者协议一致但角色相反,不能混用同一套逻辑。C# 里没有“WebHook SDK”,只有 HTTP 基础设施,用对了就稳,用错了就 400/500 静默失败。
接收 WebHook:用 ASP.NET Core Minimal API 或 Controller 处理 POST
企业微信、钉钉、飞书的机器人回调(如群事件、审批完成)都是标准 HTTP POST,body 是 JSON,Content-Type 是 application/json。别写 HttpListener 或自建监听器,太重且难维护。
- Minimal API 示例(.NET 6+):
app.MapPost("/webhook", async (HttpContext ctx) => { using var reader = new StreamReader(ctx.Request.Body, Encoding.UTF8); string json = await reader.ReadToEndAsync(); var payload = JsonSerializer.Deserialize<jsonelement>(json); // 检查 signature / timestamp / msgtype 等字段 if (payload.GetProperty("msgtype").GetString() == "event") { // 处理事件,比如审批通过后触发工单 } return Results.Ok(new { code = 0, msg = "success" }); });</jsonelement> - 必须校验签名(如果平台要求):钉钉加签、企业微信签名、飞书 tenant_access_token 都得在
ctx.Request.Headers或 query string 里取值,拼接规则错一个字符(比如用了\r\n而非\n)就验不过 - 响应体必须是 JSON,且状态码为 200;返回 HTML、空 body、或 201 都可能被平台判定为失败并重试
发送 WebHook:HttpClient 复用 + UTF8 编码 + 正确 JSON 结构
发消息不是“调个接口”,而是构造合法 payload 并确保传输层不出错。常见失败不是代码逻辑问题,而是序列化或 header 设置偏差。
-
HttpClient必须复用(static readonly或 DI 注入),否则高并发下 socket 耗尽,报SocketException: Too many open files - JSON 序列化必须用
Encoding.UTF8,否则中文变???或直接 400;推荐用System.Text.Json,别用Newtonsoft.Json默认设置(容易忽略编码) - 企业微信文本消息字段是
text.content,Markdown 是markdown.content;填反了 HTTP 返回 200 但群里没推送,排查时要抓响应里的errcode字段(0=成功,非0=失败原因) - 图片消息不传文件,只传
base64和原始字节的md5字符串(不是文件路径!不是 URL!)
签名验证失败的三个高频点
签名不是“加个参数就行”,而是平台和你两边按完全相同规则算出来的哈希值。错一点就全盘失效。
- 企业微信签名:拼接
timestamp + "\n" + secret,\n是 LF(不是 CRLF),末尾不能有空格,SHA256 后 hex 编码转小写,再拼到 URL 的sign=xxx - 钉钉加签:时间戳单位是毫秒(
DateTimeOffset.Now.ToUnixTimeMilliseconds()),拼接字符串是timestamp+"\n"+secret,HMAC-SHA256 后 Base64 编码,再 URL Encode(+→%2B,/→%2F) - 飞书签名:不用自己算,靠
tenant_access_token换取image_key后,发图消息才需带Authorization: Bearer xxx;文本消息无需签名,但必须带Content-Type: application/json
调试时最容易忽略的细节
WebHook 不像普通 API 调试能立刻看到错误,失败往往静默发生。真出问题时,第一反应不该是改业务逻辑,而是确认传输层是否干净。
- 用 Fiddler 或 Wireshark 抓包看真实请求:确认
Content-Type是application/json,body 是合法 JSON,没多余换行或 BOM - 企业微信响应里
errcode为 60020 表示 JSON 格式错误,60138 表示content字段缺失——不是“内容为空”,是字段根本没出现在 JSON 里 - 本地测试 WebHook 接收端,用
curl模拟 POST,避免前端 JS 或中间件干扰:curl -X POST http://localhost:5000/webhook \ -H "Content-Type: application/json" \ -d '{"msgtype":"text","text":{"content":"test"}}'










