后端即时通讯金融科技【免费下载链接】WeiXinMPSDK微信全平台 .NET SDK Senparc.Weixin for C#支持 .NET Framework 及 .NET Core、.NET 10.0。已支持微信公众号、小程序、小游戏、微信支付、企业微信/企业号、开放平台、JSSDK、微信周边等全平台。 WeChat SDK for C#.项目地址https://gitcode.com/gh_mirrors/we/WeiXinMPSDK点击查看免费下载Senparc.Weixin 是覆盖微信公众号、小程序/小游戏、企业微信、微信支付V2/V3、开放平台、JSSDK 等全平台的 .NET SDK当前仓库已同时支持 .NET Framework 4.6.2 与 .NET 8.0/.NET 10.0 多目标框架。本文以仓库根目录 readme.md 为主线结合 Samples/MP/Senparc.Weixin.Sample.MP 官方示例与 src 下的源码实现完整走通注册服务 → 调用高级接口 → 处理消息对话三步开发流程并给出模块类库选型、源码目录结构、分支策略与部署方式的系统说明。一、项目定位一套 SDK 覆盖微信全平台README 的核心表述是使用 Senparc.Weixin 可以方便快速地开发微信全平台应用包括微信公众号、小程序、小游戏、企业微信/企业号、开放平台、微信支付、JS-SDK、微信周边等。其几个关键设计取向值得先理解全框架兼容同时支持 .NET 3.5/4.0/4.5、.NET Standard 2.x、.NET Core 2.x/3.x、.NET 6.0/7.0/8.0/10.0README 中列出的完整矩阵兼容 MVC、Razor、WebApi、Console 命令行、桌面应用.exe、Blazor、MAUI、后台服务等环境与外部框架完全解耦SDK 本身不绑定特定 Web 框架通过Senparc.Weixin.AspNet等支撑类库接入 ASP.NET 生态AccessToken 全生命周期托管调用任意接口只需提供 AppIdSDK 自动获取并刷新 AccessToken开发者无需处理过期问题接口命名对齐官方 API 路径命名空间与参数命名尽量和微信官方文档保持一致便于在源码中快速定位接口。README 中特别强调的几点功能支持已支持大部分微信 8.x API自定义/个性化菜单、模板消息、素材、群发、多客服、支付、微小店、卡券、发票等支持用户会话上下文解决服务器无法用 Session 处理用户信息的问题支持分布式缓存及缓存策略扩展默认本地缓存、Redis、Memcached可自由扩展开发过程无需关心缓存类型可在配置文件或运行过程中自由切换。二、各模块类库与 NuGet 包选型README 的各模块类库表格是选包的核心依据整理如下DLL 对应 src 下的源码目录模块功能DLL源码位置基础库Senparc.Weixin.dllsrc/Senparc.Weixin微信公众号 / JSSDK / 摇周边等Senparc.Weixin.MP.dllsrc/Senparc.Weixin.MP微信小程序支持小游戏Senparc.Weixin.WxOpen.dllsrc/Senparc.Weixin.WxOpen微信支付 V2Senparc.Weixin.TenPay.dllsrc/Senparc.Weixin.TenPay微信支付 V3Senparc.Weixin.TenPayV3.dllsrc/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3ASP.NET MVC 扩展Senparc.Weixin.MP.Mvc.dllsrc/Senparc.Weixin.MP.MvcExtension企业微信Senparc.Weixin.Work.dllsrc/Senparc.Weixin.Work微信开放平台Senparc.Weixin.Open.dllsrc/Senparc.Weixin.OpenRedis 分布式缓存Senparc.Weixin.Cache.Redis.dllsrc/Senparc.Weixin.CacheMemcached 分布式缓存Senparc.Weixin.Cache.Memcached.dllsrc/Senparc.Weixin.CacheWebSocket独立项目Senparc.WebSocket.dllsrc/Senparc.WebSocketAll In One 集成库Senparc.Weixin.All.dllsrc/Senparc.Weixin.All版本兼容要点来自 README 的告警区块自 2019 年 5 月 1 日起 .NET Framework 3.5/4.0 停止更新自 2022 年 4 月 3 日起 .NET Framework 4.5 升级为 4.6.2若仍在使用 .NET FrameworkREADME 建议在官方停止对 4.6.2 支持之前完成向 4.8 的升级评估。使用Senparc.Weixin.All集成库可一次性自动引用所有模块是快速起步最省事的方案。各模块的 NuGet 安装命令可在 Package Manager Console 中执行例如# 基础库 公众号 Install-Package Senparc.Weixin Install-Package Senparc.Weixin.MP # 或一次性引入全部模块 Install-Package Senparc.Weixin.All三、配置体系appsettings.json 中的两个配置节所有 Sample 的配置结构高度一致。以 Samples/MP/Senparc.Weixin.Sample.MP/appsettings.json 为例其中包含两个关键配置节{ //CO2NET 设置 SenparcSetting: { IsDebug: true, DefaultCacheNamespace: DefaultCache, //分布式缓存 Cache_Redis_Configuration: #{Cache_Redis_Configuration}#, //Redis配置 Cache_Memcached_Configuration: #{Cache_Memcached_Configuration}#, //Memcached配置 SenparcUnionAgentKey: #{SenparcUnionAgentKey}# }, //Senparc.Weixin SDK 设置 SenparcWeixinSetting: { //微信全局 IsDebug: true, //公众号 Token: #{Token}#, EncodingAESKey: #{EncodingAESKey}#, WeixinAppId: #{WeixinAppId}#, WeixinAppSecret: #{WeixinAppSecret}# } }配置规则有三条README 与源码注释共同印证信息自动识别以上 key 会被 SDK 自动识别不用的参数可以删除但修改 key 后将无法自动识别占位符说明#{xxx}#是 Azure DevOps 的默认占位符格式。仓库中的 Sample 为了保密使用了占位符实际使用时请整体替换为明文如Token: MyFullToken不要留空字符串SenparcWeixinSetting中所有字符串值都可能被用于字典索引例如以 AppId 为键的多账号容器因此宁可删除整条配置也不要留空串。从源码看src/Senparc.Weixin.AspNet/RegisterServices/SenparcWeixinRegisterServiceExtension.cs 的AddSenparcWeixin()方法通过configuration.GetSection(SenparcWeixinSetting)完成SenparcWeixinSetting的绑定并自动注册 CO2NET 全局服务同文件的注释区块L120-L166还给出了完整的多平台配置模板包括公众号WeixinAppId/WeixinAppSecret/Token/EncodingAESKey、小程序WxOpenAppId/WxOpenAppSecret、企业微信WeixinCorpId/WeixinCorpSecret、微信支付 V2WeixinPay_PartnerId/WeixinPay_Key、微信支付 V3TenPayV3_MchId/TenPayV3_Key等、开放平台Component_Appid/Component_Secret/Component_Token/Component_EncodingAESKey以及分布式缓存Cache_Redis_Configuration等全部字段。该文件同时实现了微信支付 V3 证书 HttpClient 的自动注册逻辑L96-L109当检测到TenPayV3_CertPath配置时自动生成注册密钥并注册带证书的 HttpClient。四、Hello World两步启动 一句接口调用这是 README 的核心实战章节以下代码全部继承自 Samples/MP/Senparc.Weixin.Sample.MP/Program.cs.NET 10 Minimal Hosting 风格。第 1 步注册服务builder.Build() 之前// Senparc.Weixin 注册必须 builder.Services.AddSenparcWeixin(builder.Configuration);对应旧格式 Startup.cs 项目此代码放在ConfigureServices()内。注意 Sample 的 Program.cs 中还有一行builder.Services.AddMemoryCache();——注释明确标注使用内存缓存必须添加这是本地缓存策略的前置依赖。第 2 步启用配置并注册账号builder.Build() 之后// 启用微信配置必须 var registerService app.UseSenparcWeixin(app.Environment, null /* 传入 null 则使用 appsettings 中的 SenparcSetting 配置 */, null /* 传入 null 则使用 appsettings 中的 SenparcWeixinSetting 配置 */, register { /* CO2NET 全局配置 */ }, (register, weixinSetting) { // 注册公众号账号信息可以执行多次注册多个公众号 register.RegisterMpAccount(weixinSetting, 【盛派网络小助手】公众号); });对应旧格式 Startup.cs 项目此代码放在Configure()内。README 给出的简化版写法两参app.UseSenparcWeixin(app.Environment, null, null, ...)与 Sample 实际五参重载的区别在于后者显式多传了一个 CO2NET 全局配置委托。如果希望自动注册所有已配置的平台账号可引入Senparc.Weixin.All包并追加autoRegisterAllPlatforms: true参数var registerService app.UseSenparcWeixin(app.Environment, null, null, register { }, (register, weixinSetting) { /* 无需手动注册 */ }, autoRegisterAllPlatforms: true /* 自动注册所有平台 */ );从源码看该参数定义在 src/Senparc.Weixin.All/WeixinEntensions.cs 中方法注释写明是否从 appsettings.json 中自动注册所有平台Open 平台除外UseSenparcWeixin()的核心重载则位于 src/Senparc.Weixin/Senparc.Weixin/WeixinRegister.cs。调用高级接口只需 1 句代码注册完成后可在程序任意位置直接调用微信接口以客服接口为例await CustomApi.SendTextAsync(AppId, OpenId, Hello World!);README 的四条提示在此对应到源码事实AccessToken 自动托管CustomApisrc/Senparc.Weixin.MP/Senparc.Weixin.MP/AdvancedAPIs/Custom/CustomApi.cs内部通过容器自动获取 AccessToken只需提供 AppIdAppId 可从配置自动获取注册信息存放于Senparc.Weixin.Config.SenparcWeixinSetting参数值来自appsettings.jsonSample 中即有private string appId Config.SenparcWeixinSetting.MpSetting.WeixinAppId;的用法见 CustomMessageHandler.cs L49同步方法同样可用如Senparc.Weixin.MP.AdvancedAPIs.CustomApi.SendText()命名空间对齐官方 API 路径参数命名尽量与官方文档一致便于定位与测试。README 在此处给出结论至此已可举一反三调用所有微信模块的接口各模块公众号、小程序、企业微信、微信支付的调用方式基本一致。五、公众号消息对话自定义 MessageHandler 中间件公众号默认提供对话窗口可发送文字、图片、语音等类型消息与程序互动。该方案同样适用于企业微信和小程序客服消息。官方示例采用两步完成。第 1 步创建自定义 MessageHandler继承MessageHandlerDefaultMpMessageContext重写对应请求类型的处理方法。官方 Sample 的 CustomMessageHandler.cs 是完整的可运行实现其骨架如下public partial class CustomMessageHandler : MessageHandlerDefaultMpMessageContext { public CustomMessageHandler(Stream inputStream, PostModel postModel, int maxRecordCount 0, bool onlyAllowEncryptMessage false, IServiceProvider serviceProvider null) : base(inputStream, postModel, maxRecordCount, onlyAllowEncryptMessage, serviceProvider: serviceProvider) { } /// summary /// 所有未处理类型的默认消息 /// /summary public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage) { //ResponseMessageText也可以是News等其他类型 var responseMessage this.CreateResponseMessageResponseMessageText(); responseMessage.Content 你发送了一条消息但程序没有指定处理过程; return responseMessage; } public override TaskIResponseMessageBase OnImageRequestAsync(RequestMessageImage requestMessage) { //处理图片请求... } public override TaskIResponseMessageBase OnLocationRequestAsync(RequestMessageLocation requestMessage) { //处理地理位置请求... } }关键机制Sample 源码注释与原类说明一致DefaultResponseMessage是必须重写的兜底方法所有OnXXRequestAsync方法都是虚方法不重写则默认落入DefaultResponseMessage的结果。Sample 中还演示了两个进阶能力关键字链式处理requestMessage.StartHandler().Keyword(关键字1, ...).Keywords(new[]{...}, ...).Regex(^\d#\d$, ...).Default(...)提供按序匹配的关键字、多关键字、正则、默认分支处理匹配成功后不再执行后续逻辑用户上下文GlobalMessageContext.ExpireMinutes 3设置消息上下文有效期base.GlobalMessageContext.GetMessageContext(requestMessage)可取出会话上下文含历史RequestMessages在OnExecutingAsync/OnExecutedAsync中通过StorageData演示了跨请求存储用户状态这正是 README 所说用户会话上下文能力的落点。第 2 步通过中间件请求 CustomMessageHandlerSDK 提供中间件推荐和Controller或 WebApi两种方式请求 MessageHandler任选其一。以中间件为例在 Program.cs 启用配置后注册app.UseMessageHandlerForMp(/WeixinAsync, (stream, postModel, maxRecordCount, serviceProvider) new CustomMessageHandler(stream, postModel, maxRecordCount, false, serviceProvider), options { options.AccountSettingFunc context Senparc.Weixin.Config.SenparcWeixinSetting; });Sample 的 Program.csL49-L59在此之外还演示了超长文本自动分片// [可选] 设置文本返回长度限制如需超长消息可通过客服接口分段回复 options.TextResponseLimitOptions new TextResponseLimitOptions(2048, weixinSetting.WeixinAppId);这对应 README 公告中提到的全面支持长文本自动分片发送能力——回复文本超过 2048 字符时自动通过客服接口分段续发无需业务代码介入。中间件实现源码位于 src/Senparc.Weixin.MP.Middleware/MessageHandlers/Middleware/MpMessageHandlerMiddleware.cs。配置完成后将https://YourDomain/WeixinAsync填入微信公众号后台【设置与开发】【基本配置】 服务器地址(URL)对应的 Token 在 appsettings.json 中设置。企业微信和小程序同理参考 Samples 下对应示例。README 同时说明若需对整个消息处理步骤做更细致控制或在 .NET Framework 中使用可采用Controller或 WebApi方式典型流程为三步各一行代码——接收new CustomMessageHandler(Request.InputStream, postModel)、处理messageHandler.Execute()、返回return new FixWeixinBugWeixinResult(messageHandler)并强调每次 Post 请求都必须重新执行CheckSignature.Check(...)验签防止请求伪造。六、src 与 Samples 目录结构说明src 文件夹源码项目布局文件夹说明src/Senparc.WebSocketWebSocket 模块src/Senparc.Weixin.CacheSenparc.Weixin.Cache.Memcached.dll、Senparc.Weixin.Cache.Redis.dll 等分布式缓存扩展方案含 CsRedis、Dapr 变体src/Senparc.Weixin.AspNet专为 Web 提供支撑的类库注册扩展、结果类型等src/Senparc.Weixin.MP.MvcExtension为 MVC 项目提供的扩展包src/Senparc.Weixin.MP微信公众账号 SDK 源代码src/Senparc.Weixin.MP.Middleware微信公众账号消息中间件源代码src/Senparc.Weixin.Open第三方开放平台 SDK 源代码src/Senparc.Weixin.TenPay微信支付 V2 与 V3 的源代码src/Senparc.Weixin.Work企业微信 SDK 源代码src/Senparc.Weixin.Work.Middleware企业微信消息中间件源代码src/Senparc.Weixin.WxOpen微信小程序 SDK 源代码包括小游戏src/Senparc.Weixin.WxOpen.Middleware微信小程序消息中间件源代码包括小游戏src/Senparc.Weixin所有 Senparc.Weixin.[x].dll 基础类库源代码Samples 文件夹可直接运行的代码模板所有模块的用法保持高度一致配置过程、AccessToken 管理、消息处理、服务消息、接口调用等。只需参考任意一个模块推荐从公众号或小程序开始即可举一反三。各 Sample 直接打开对应文件夹下的.sln即可查看源码运行即可看到说明文档文件夹说明SDK 引用方式Samples/MP公众号NuGet 包Samples/TenPayV2微信支付 V1 和 V2NuGet 包Samples/TenPayV3微信支付 V3TenPay APIv3NuGet 包Samples/Work企业微信NuGet 包Samples/WxOpen微信小程序NuGet 包Samples/Shared所有 Sample 共享文件—Samples/All微信公众号、小程序、微信支付、企业微信等所有功能的混合场景演示适合集成多平台或深度开发场景进阶┣ Samples/All/console命令行 Console Demo.NET CoreNuGet 包┣ Samples/All/net45-mvc可直接发布使用的 Demo.NET Framework 4.5 ASP.NET MVCNuGet 包┗ Samples/All/net10-mvc可直接发布使用的 Demo.NET 10.0兼容 .NET 5.0-8.0 和 .NET Core源码最新┗ Samples/All/net8-mvc可直接发布使用的 Demo.NET 8.0兼容 .NET 5.0-7.0 和 .NET Core源码最新解决方案入口.NET 10.0 打开 Samples/All/net10-mvc/Senparc.Weixin.Sample.Net10.sln.NET 8.0 打开 Samples/All/net8-mvc 下的 sln.NET Framework 打开 Samples/All/net45-mvc/Senparc.Weixin.MP.Sample.Net45.sln命令行 Demo 见 Samples/All/console。七、编译发布、分支策略与部署自编译生成 NuGet 包README 说明打开net10-mvc解决方案即可看到所有源码当编译模式为Release时将自动生成本地 NuGet 包默认生成到/src/BuildOutPut/文件夹下。也就是说既可以 NuGet 直接安装也可以修改源码后本地编译验证。分支策略README 各重要分支说明表分支说明master正式发布的主分支通常比较稳定可用于生产环境Developer开发分支通常为 Beta 版本新版本先在此分支开发最后推送稳定版到 master建议 Pull Request 提交到此分支而不是 masterBookVersion1《微信开发深度解析》图书出版时对应代码快照DotNET-Core_MySQL.NET Core 环境下的 Pomelo.EntityFrameworkCore.MySql 框架集成演示分支NET4.0仅支持 .NET 4.0 的分支2017 年停止更新NET3.5仅支持 .NET 3.5 的分支2015 年停止更新部署方式README 给出两条路径Azure App ServiceAzure 对 .NET 有很好的支持部署步骤见官方 Wiki《将微信站点部署到 Azure 中》任意服务器 FTP在 Web 服务器上安装 FTP 服务如 FileZilla Server直接上传本地编译好的代码。Samples/All/net10-mvc编译后即可直接使用无需修改代码使用 Azure App Service 或其他云服务时通常 FTP 也是开通的。贡献代码流程Fork → 创建特性分支git checkout -b my-new-feature→ 提交改动git commit -am Added some feature→ 推送远程git push origin my-new-feature→ 在Developer分支发起 Pull Request不要直接提交到master。八、进阶参考与项目约定完整开发文档docs 目录提供分模块mp/wxopen/work/tenpayv2/tenpayv3的更完整开发说明供进阶开发使用中英文版本齐全测试账号体验README 提供盛派网络小助手公众号/小程序SenparcRobot用于体验全部功能编码规范仓库 规范文档 目录下维护了异步方法标记规范、文件头标注规范如各源文件头部的 Apache 2.0 许可声明与创建标识/修改标识注释格式在 CustomMessageHandler.cs 等文件头可见等约束参与贡献前应阅读许可项目采用 Apache License Version 2.0100% 开源、支持商用详见 license.md。小结本文按 readme.md 的原始脉络走完了 Senparc.Weixin 的完整上手路径从appsettings.json的SenparcWeixinSetting/SenparcSetting双配置节到AddSenparcWeixin()UseSenparcWeixin()RegisterMpAccount()三步启动到CustomApi.SendTextAsync()一句代码调用接口再到MessageHandlerDefaultMpMessageContext子类 UseMessageHandlerForMp()中间件的消息对话闭环。每个步骤都可在 Samples/MP/Senparc.Weixin.Sample.MP 中找到可运行代码在 src 中找到对应实现由于各平台模块小程序、企业微信、微信支付等的配置、注册、接口调用方式与公众号保持一致掌握本文流程后即可平移到其余所有模块。赞分享后端即时通讯金融科技【免费下载链接】WeiXinMPSDK微信全平台 .NET SDK Senparc.Weixin for C#支持 .NET Framework 及 .NET Core、.NET 10.0。已支持微信公众号、小程序、小游戏、微信支付、企业微信/企业号、开放平台、JSSDK、微信周边等全平台。 WeChat SDK for C#.项目地址https://gitcode.com/gh_mirrors/we/WeiXinMPSDK点击查看免费下载相关推荐Senparc.Weixin 微信全平台 .NET SDK 实战指南从三行代码到生产级消息服务Senparc.Weixin 微信全平台 .NET SDK 实战指南从三行代码到生产级消息服务 本文基于仓库根目录的 readme.en.md https:/后端即时通讯金融科技ESP32开源无人机开发指南从硬件到代码的完整实现路径ESP32开源无人机开发指南从硬件到代码的完整实现路径 一、无人机开发的痛点与解决方案 传统方案的局限 当你尝试进入无人机开发领域时通常会面临三个核心障碍智能硬件嵌入式物联网Chalk.ist实战指南从代码到精美图片的完整路径Chalk.ist实战指南从代码到精美图片的完整路径 Chalk.ist是一个基于Nuxt.js构建的开源工具专门用于将源代码转换为精美的图片格式。无论是分上一篇告别网盘限速困扰LinkSwift 网盘直链下载助手终极指南下一篇如何用LinkSwift解锁九大网盘下载完整配置与实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
DeskcommCRM实战:从部署到客户全生命周期管理的销售中枢解析 1. 为什么最终押注DeskcommCRM作为销售团队的中枢我所在的团队大概在半年前做了一次CRM系统的整体切换,之前用的是那种"客户信息表格化"的轻量工具:能存联系人、能记跟进记录、能导出Excel。听起来够用,但实际跑起来问题越来越多—… · 2026/9/25 13:58:22
手机号归属地查询:MySQL号段表设计与查询优化实战 简介:这是一份面向数据库初学者与数据分析人员的MySQL手机号归属地查询数据集,适合用于练习SQL查询、批量统计与隐私合规处理。压缩包内共1个文件,为phone_msg.sql格式的SQL脚本,整体约2.22MB,导入MySQL后即可获得手机… · 2026/9/25 13:58:22
桌面端CRM实践:DeskcommCRM从部署到核心业务流程配置全解析 1. 为什么桌面端还需要一个专门的CRM做销售管理和客户运营的人,大概率都经历过这种场景:电话刚挂断,销售在Excel里翻半天找客户历史记录;客服在微信、邮件、电话三个窗口来回切,最后客户问了句“我上次反馈的问题处理到… · 2026/9/25 14:27:59
DeskcommCRM实战:从选型配置到落地运营的完整指南 DeskcommCRM 这个名字,我第一次听到的时候以为又是一套中规中矩的客户关系管理系统,结果用下来才发现,它把“桌面办公”和“客户沟通”这两件本该强绑定、却总被拆开的事,真正揉到了一起。它解决的核心问题很直接:业务… · 2026/9/25 14:27:59
DeskcommCRM落地实践:客户管理、销售跟进与通讯集成全流程指南 1. 为什么最后是DeskcommCRM,而不是那堆大牌CRM上季度末我翻着销售团队的Excel和微信聊天记录,花了大半个下午才拼出一个重点客户的完整跟进史——谁来签的、答应过什么、上次谈到哪一步,全要靠猜。那一刻我意识到,不是团队不努力… · 2026/9/25 14:27:53
Manus学习手册 (AI工具篇二):用 TaoToken 统一 Key 打通 Agent 工作流 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 14:27:03
Ruckus胖AP配置全流程:从背靠背开局到CLI固件升级避坑指南 简介:这份PPT文档面向无线网络运维人员与网络工程师,系统讲解Ruckus胖AP的配置方法,帮助解决设备初次上线、信道规划与安全加密等常见问题。资源包共1个文件,为pptx演示文稿,大小约1MB,以图文步骤形式呈现配… · 2026/9/25 14:27:03
AI Agent 开发完整技术栈 工具清单:TaoToken 统一 Key 接入配置骨架 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 14:26:56
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37