API网关后端微服务【免费下载链接】Ocelot.NET API Gateway项目地址https://gitcode.com/gh_mirrors/oc/Ocelot点击查看免费下载本篇指南以 Ocelot 官方文档首页docs/index.rst为骨架系统梳理 Ocelot 25.0 的文档体系与核心内容从面向微服务架构的大图景设计、快速上手三行配置到两大主特性配置与路由再到 27 项按字母序排列的功能特性和构建流程。读完本文你将掌握 Ocelot 文档的导航逻辑、各特性章节的主题与定位并了解如何结合仓库源码src/、samples/、test快速定位实现细节为选型与落地提供完整路径图。一、这份文档索引是什么Ocelot 25.0 的特性地图docs/index.rst是 Ocelot 官方文档基于 Sphinx/reStructuredText 构建参见 docs/readme.md的入口页面。它本身不讲解某个具体功能而是承担三层职责版本指引明确当前文档对应 Ocelot25.0版本阅读路线建议给新用户推荐 Introduction 章节docs/introduction/bigpicture.rst给生产环境用户强调升级前必读 发布说明完整目录树toctree按Welcome / Introduction / Features / Building Ocelot四组列出全部 27 个特性章节与 3 个构建章节。这份索引的价值在于它揭示了项目团队对文档的组织方式——所有特性按字母序排列并明确指出Configuration配置与 Routing路由是两大 primary features主特性其余特性围绕它们扩展。阅读仓库中的任一功能代码时先回到这张特性地图定位对应章节是最高效的路径。二、Ocelot 的定位与大图景Introduction 章节2.1 适用场景与技术底座按 大图景章节 的说明Ocelot 面向使用 .NET 构建微服务SOA架构、需要一个统一入口API Gateway的团队它只要求上下游通信走 HTTP(S)可在 ASP.NET Core 支持的任意平台上运行。从实现上看Ocelot 本质上是一组按特定顺序排列的 ASP.NET Core 中间件它会按配置不断改写HttpRequest对象直到某个请求构建中间件将其转换为HttpRequestMessage真正发起下游请求的中间件是管道中最后一个节点不再调用下一个中间件下游响应沿管道原路返回由专门的中间件把HttpResponseMessage映射回HttpResponse返回给客户端。这一机制在源码中对应 OcelotPipelineExtensions.cs管线组装与 DownstreamUrlCreatorMiddleware.cs、Requester 中间件请求构建与发送等实现。2.2 四种典型部署拓扑bigpicture.rst用 4 张架构图说明常见部署形态图片位于 docs/images/拓扑说明配图Basic Implementation单实例网关直连下游服务OcelotBasic.jpgMultiple Instances网关多实例横向扩展OcelotMultipleInstances.jpgWith Consul网关多实例 Consul 服务发现OcelotMultipleInstancesConsul.jpgWith Service Fabric集成 Azure Service FabricOcelotServiceFabric.jpg其中多实例 Consul 场景正是 服务发现特性 的典型用途Consul 同时还能充当配置 KV 存储见下文配置的多种存储形态。三、快速上手从空项目到第一条路由Getting Started 章节 给出了完整的上手路径配套真实可运行的 Basic 示例。3.1 目标框架与安装Ocelot 25.0 面向 ASP.NET Core目标框架为 .NET 8LTS、.NET 9STS与 .NET 10LTS。安装方式dotnet add package Ocelot推荐使用ASP.NET Core Empty模板创建最小 API 项目但不要添加app.Map*端点映射方法——Ocelot 的中间件管线与 Minimal API 端点不兼容这也是入门章节强调的硬性约束。3.2 最小配置四段式 JSON入门章节给出了两个配置文件。第一份是能启动但什么都不做的最小骨架{ Aggregates: [], // optional Routes: [], // required section DynamicRoutes: [], // optional section GlobalConfiguration: { // required BaseUrl: https://api.mybusiness.com } }第二份是真正转发请求的示例与 samples/Basic/ocelot.json 一致{ Routes: [ { UpstreamHttpMethod: [ Get ], UpstreamPathTemplate: /ocelot/posts/{id}, DownstreamPathTemplate: /todos/{id}, DownstreamScheme: https, DownstreamHostAndPorts: [ { Host: jsonplaceholder.typicode.com, Port: 443 } ] } ], GlobalConfiguration: { BaseUrl: https://api.mybusiness.com } }BaseUrl是最需要留意的属性Ocelot 需要知道自身对外的 URL用于 Header 查找替换HeaderFindAndReplace和部分管理 APIAdministration配置。它应填客户端实际访问的外部地址——例如容器内 Ocelot 跑在http://123.12.1.2:6543前面有 nginx 以https://api.mybusiness.com对外响应则BaseUrl填https://api.mybusiness.com。多实例部署时建议通过脚本在命令行注入真实 IP。3.3 启动代码Program.cs 三步走入门章节给出的 Program.cs 完整代码如下仓库中 Basic 示例与文档完全一致using Ocelot.DependencyInjection; using Ocelot.Middleware; var builder WebApplication.CreateBuilder(args); // Ocelot Basic setup builder.Configuration .SetBasePath(builder.Environment.ContentRootPath) .AddOcelot(); // single ocelot.json file in read-only mode builder.Services .AddOcelot(builder.Configuration); // Add your features if (builder.Environment.IsDevelopment()) { builder.Logging.AddConsole(); } // Add middlewares aka app.Use*() var app builder.Build(); await app.UseOcelot(); await app.RunAsync();关键点builder.Configuration.AddOcelot()以只读方式加载单个ocelot.jsonbuilder.Services.AddOcelot(builder.Configuration)向 DI 容器注册 Ocelot 必需与默认服务await app.UseOcelot()组装全部 Ocelot 中间件必须先 await 再RunAsync()不要调用app.MapGet()等端点方法。四、两大主特性之一Configuration配置配置章节 是索引页点名的两大主特性之首内容也最厚超过 1200 行。核心脉络如下。4.1 四大配置区块与各自职责{ Routes: [], // static routes网关如何对待上游请求的静态对象 DynamicRoutes: [], // 动态路由配合服务发现 provider 使用 Aggregates: [], // 聚合路由BFF把多个普通路由响应合成一个 JSON 对象 GlobalConfiguration: {} // 全局配置可覆盖静态路由级设置的兜底区 }各区块的 JSON 模型类分别位于 src/Configuration/File/FileRoute.cs、FileDynamicRoute.cs、FileAggregateRoute.cs、FileGlobalConfiguration.cs。4.2 Route 完整 Schema文档给出了FileRoutesrc/Configuration/File/FileRoute.cs对应的全部顶层属性完整 31 项下面按用途分组列出路由匹配UpstreamPathTemplate、UpstreamHttpMethod、UpstreamHost、UpstreamHeaderTemplates、RouteIsCaseSensitive、Priority下游转发DownstreamPathTemplate、DownstreamScheme、DownstreamHostAndPorts、DownstreamHttpMethod、DownstreamHttpVersion、DownstreamHttpVersionPolicy请求/响应改写AddClaimsToRequest、AddHeadersToRequest、AddQueriesToRequest、ChangeDownstreamPathTemplate、UpstreamHeaderTransform、DownstreamHeaderTransform、RouteClaimsRequirement横切能力AuthenticationOptions、CacheOptions、HttpHandlerOptions、LoadBalancerOptions、QoSOptions、RateLimitOptions、SecurityOptions、Timeout、RequestIdKey、DangerousAcceptAnyServerCertificateValidator扩展与标识DelegatingHandlers、Key、Metadata、ServiceName、ServiceNamespace。重要弃用提示FileCacheOptions旧缓存配置段自 24.1 起弃用25.0 中已移除请改用CacheOptions。这一点在FileRoute.cs源码中直接用[Obsolete(Use CacheOptions instead of FileCacheOptions! ...)]特性标注src/Configuration/File/FileRoute.cs#L40-L41与文档互为印证。4.3 多环境配置与配置合并与任何 ASP.NET Core 项目一样Ocelot 支持环境化配置文件var builder WebApplication.CreateBuilder(args); builder.Configuration .SetBasePath(builder.Environment.ContentRootPath) .AddJsonFile(ocelot.json) // primary config file .AddJsonFile($ocelot.{builder.Environment.EnvironmentName}.json); builder.Services .AddOcelot(builder.Configuration);更 Ocelot 化的做法是使用AddOcelot(builder.Environment)它按正则^ocelot\.(.*?)\.json$发现并合并所有ocelot.*.json文件跳过环境专属文件合并结果写回ocelot.json作为运行时的唯一事实来源若想设置GlobalConfiguration必须准备一个ocelot.global.json文件。合并逻辑的实现见 ConfigurationBuilderExtensions.cs其中MergeOcelotJson枚举ToFile/ToMemory控制写回磁盘还是仅驻留内存src/DependencyInjection/MergeOcelotJson.cs。合并到内存的典型场景是无磁盘写权限的云环境Azure/AWS/GCP与 Dockerbuilder.Configuration .SetBasePath(builder.Environment.ContentRootPath) .AddOcelot(builder.Environment, MergeOcelotJson.ToMemory);合并时机注意合并只发生在应用启动阶段启动后ocelot.json即保持静态运行期热更新请改用配置重载见 4.5。4.4 配置的多种存储形态文档把配置来源归纳为四类互相补充存储形态用法说明单文件AddOcelot()只读ocelot.json多文件合并AddOcelot(folder, env)/AddOcelot(env, mergeTo)按正则合并ocelot.*.json可写盘或留内存代码构造AddOcelot(fileConfiguration)运行时以FileConfiguration对象注入Build From Scratch 小节Consul KV服务发现章节sd-consul-configuration-in-kv把配置存到 Consul KV 存储从零构建形态的最终 .NET 8 写法using Ocelot.Configuration.File; using Ocelot.DependencyInjection; using Ocelot.Middleware; var builder WebApplication.CreateBuilder(args); var config new FileConfiguration(); // create new or read static state from anywhere // ... initialize or rewrite props: add routes, global config, etc. builder.Configuration .SetBasePath(builder.Environment.ContentRootPath) .AddOcelot(config) // MergeOcelotJson.ToFile : writing config JSON back to disk .AddOcelot(config, builder.Environment, MergeOcelotJson.ToMemory); // merging to memory builder.Services .AddOcelot(builder.Configuration); var app builder.Build(); await app.UseOcelot(); await app.RunAsync();AddOcelot的全部重载签名都可以在 ConfigurationBuilderExtensions.cs 中找到含optional、reloadOnChange可选参数。4.5 热重载与变更响应重载reload on change自 23.2 起AddOcelot系列方法提供reloadOnChange参数推荐用它代替原生AddJsonFileconfig.AddOcelot(env, mergeTo, optional: false, reloadOnChange: true);主动响应变更React to Changes从 DI 容器解析IOcelotConfigurationChangeTokenSource实现位于 src/Configuration/ChangeTracking/既可轮询ChangeToken.HasChanged也可注册RegisterChangeCallback回调。文档提供了完整的BackgroundService轮询示例与回调类示例见 配置章节 的 React to Changes 小节。4.6 常用路由级选项速查HttpHandlerOptions基于SocketsHttpHandlerHttpHandlerOptions: { AllowAutoRedirect: false, MaxConnectionsPerServer: 2147483647, // max integer PooledConnectionLifetimeSeconds: 120, UseCookieContainer: false, UseProxy: false, UseTracing: false }各选项默认值AllowAutoRedirectfalse是否跟随 3xx 重定向、MaxConnectionsPerServer2147483647到单一下游服务器的最大连接数、PooledConnectionLifetimeSeconds120连接池中连接可复用的存活秒数默认值硬编码在 src/Configuration/HttpHandlerOptions.cs 的DefaultPooledConnectionLifetimeSeconds常量、UseCookieContainerfalse注意开启后 Ocelot 会为每个下游服务缓存HttpMessageInvoker同一下游的所有请求将共享 Cookie文档明确建议非必要不开启、UseProxyfalse、UseTracingfalse开启后接入 Tracing 特性。SSL 错误路由级设置DangerousAcceptAnyServerCertificateValidator: true可忽略自签名证书的 SSL 校验但文档强烈不推荐用于生产——仅限本地开发https/wss自签名场景生产环境必须使用权威签发的真实证书。DownstreamHttpVersion/DownstreamHttpVersionPolicy可指定下游代理请求使用的 HTTP 版本1.0/1.1/2.0DownstreamHttpVersionPolicy对应 .NET 的HttpVersionPolicy枚举用于规避 HTTP/2 场景下的PROTOCOL_ERROR——典型解法是把VersionPolicy设为RequestVersionOrHigher{ DownstreamHttpVersion: 2.0, DownstreamHttpVersionPolicy: RequestVersionOrHigher }Timeout体系四层优先级从高到低QoS 超时毫秒→ 路由级超时秒→ 全局超时秒→ 绝对默认值 90 秒由DownstreamRoute.DefaultTimeoutSeconds静态属性定义可在 Program.cs 中修改。注意 QoS 与路由级 Timeout 同时配置时路由级会被忽略并触发警告日志。超时实现的核心是 TimeoutDelegatingHandler.cs。Metadata扩展路由与全局均可定义任意键值对供中间件、Delegating Handler 等在运行时读取Metadata 特性全局值会被路由级同名键覆盖。五、两大主特性之二Routing路由路由章节 从概念、占位符、通配、优先级到查询串路由、上游主机/头路由、IP 安全选项完整覆盖了 Ocelot 的转发核心。5.1 基础路由与占位符一条路由由UpstreamPathTemplate匹配入站 URL、UpstreamHttpMethod区分同 URL 的不同动词留空则匹配所有方法以及DownstreamPathTemplate/DownstreamScheme/DownstreamHostAndPorts定义转发目标构成{ UpstreamHttpMethod: [ Get, Post ], UpstreamPathTemplate: /posts/{postId}, DownstreamPathTemplate: /api/posts/{postId}, DownstreamScheme: https, DownstreamHostAndPorts: [ { Host: localhost, Port: 80 } ] }占位符{something}必须同时出现在上、下游模板中运行时 Ocelot 会把上游路径中的值代入下游模板。路由匹配默认不区分大小写可用RouteIsCaseSensitive: true按路由开启。嵌入占位符23.4支持同一路径段内嵌入多个占位符例如模板/api/invoices_{url0}/{url1}-{url2}_abcd/{url3}?urlId{url4}对上/api/invoices_super/123-456_abcd/789?urlId987时{url0}super、{url1}123、{url2}456、{url3}789、{url4}987。空占位符23.0占位符值为空串属于受支持的边界情况——/invoices/与省略末尾斜杠的/invoices都能正确路由到下游/api/invoices。5.2 Catch All 与 Priority{ UpstreamPathTemplate: /{catchAll}, DownstreamPathTemplate: /{catchAll} }Catch All 路由的占位符名称无意义任何名称均可其优先级恒为 0硬编码。配合Priority属性可精确控制匹配顺序{ UpstreamPathTemplate: /goods/delete, Priority: 1 }当请求/goods/delete时/goods/deletePriority1会优先于/goods/{catchAll}Priority0被匹配——这在路由列表顺序不可控的场景下非常关键。5.3 查询串路由与参数合并查询参数同样支持占位符双向传递路径 → 查询串UpstreamPathTemplate: /api/units/{subscription}/{unit}/updates→DownstreamPathTemplate: /api/subscriptions/{subscription}/updates?unitId{unit}查询串 → 路径UpstreamPathTemplate: /api/subscriptions/{subscriptionId}/updates?unitId{uid}→DownstreamPathTemplate: /api/units/{subscriptionId}/{uid}/updatesCatch All 查询串/contracts?{query}→/apipath/contracts?{query}适合原样透传复杂查询如 OData 过滤器。参数合并算法由DownstreamUrlCreatorMiddleware实现见 src/DownstreamUrlCreator/DownstreamUrlCreatorMiddleware.cs按三步构造最终下游 URL先放下游模板中显式定义的参数其次追加{query}捕获的全部参数最后追加其余替换出的占位符值。由此带来两个实用技巧保留参数占位符与参数名不同名如{serverId}→server参数参数被保留删除参数占位符与参数名同名如{userId}→userId参数参数被消除比较区分大小写。注意 ASP.NET 数组模型绑定的selectedCourses1050selectedCourses2000形式会被合并丢失上游应改用selectedCourses[0]1050selectedCourses[1]2000。5.4 上游主机与上游头路由UpstreamHost按客户端Host头匹配路由未设置时任意 Host 均可匹配且两条除UpstreamHost外完全相同的路由设置了值的那条优先。UpstreamHeaderTemplates要求请求包含指定头且值匹配才命中{ UpstreamPathTemplate: /, UpstreamHeaderTemplates: { country: uk, version: v1 } }头模板还支持特殊占位符{header:placeholdername}把整个请求头值注入下游路径模板例如version: {header:versionnumber}DownstreamPathTemplate: /{versionnumber}/api。该字典同样适用于聚合路由。5.5 SecurityOptionsIP 黑白名单基于IPAddressRange库支持六种 IP 规则格式单 IP、IP 区间192.168.1.1-192.168.1.250、短区间192.168.1.1-250、子网192.168.1.0/255.255.255.0、CIDR IPv4192.168.1.0/24、CIDR IPv6fe80::/10。SecurityOptions: { IPBlockedList: [ 192.168.0.0/23 ], IPAllowedList: [192.168.0.15, 192.168.1.15], ExcludeAllowedFromBlocked: true }要点名单在配置加载时求值ExcludeAllowedFromBlocked默认 false允许大范围封锁 子范围放行该特性仅支持静态路由不适用于动态路由自 25.0 起对 WebSocket 升级请求CONNECT 方法同样生效。实现见 src/Security/。5.6 动态路由动态路由DynamicRoutes区块配合服务发现特性使用免去手工逐条配置路由的负担其完整参考见服务发现章节的 Dynamic Routing 小节。5.7 路由错误速查499 与 504文档专门收集了两个高频异常场景499Client Closed Request由OperationCanceledException触发典型原因 A客户端主动取消请求B浏览器刷新/关闭页面导致下游请求中断。建议保证客户端稳定并视场景调整路由Timeout504Gateway Timeout由TimeoutException触发典型原因是下游服务响应缓慢或大请求压垮慢下游。建议调大路由Timeout。完整错误与状态码体系见 错误码章节。六、27 项功能特性全景Features 目录索引页按字母序列出全部特性章节对应 docs/features/ 目录下的 27 个.rst文件本文按业务域归类并给出源码落点网关核心Configuration主特性见第四节Routing主特性见第五节Administration管理 API对应 src/Administration/Error Codes错误码枚举在 src/Errors/OcelotErrorCode.cs安全与身份Authentication、Authorization中间件见 src/Authentication/、src/Authorization/SecurityIP 安全策略见 src/Security/Claims Transformation、Headers Transformation、Method Transformation请求改写族通信与流量治理Load Balancer实现见 src/LoadBalancer/Rate Limiting实现见 src/RateLimiting/Quality of Service熔断器 CircuitBreakerDelegatingHandler.csCaching输出缓存中间件 OutputCacheMiddleware.csDelegating Handlers请求管道注入见 src/Requester/Timeout见 4.6聚合与 BFFAggregation聚合中间件与聚合器接口在 src/Multiplexer/GraphQLGraphQL 聚合示例见 samples/GraphQL/服务发现与云原生Service Discoveryprovider 工厂见 src/ServiceDiscovery/Service Fabric、Kubernetes示例分别见 samples/ServiceFabric/、samples/Kubernetes/可观测性与扩展Logging、Tracing实现见 src/Logging/RequestId链路标识见 src/RequestId/Metadata路由元数据扩展见 src/Metadata/Middleware Injection自定义中间件注入见 src/Middleware/Dependency InjectionIOcelotBuilder扩展体系见 src/DependencyInjection/协议与传输WebSockets代理中间件 WebSocketsProxyMiddleware.cs25.0 起支持含wss与 IP 名单约束明确不支持的能力notsupported.rstChunked EncodingOcelot 总是回填Content-Length、转发Host头、原生 Swagger 生成替代方案Postman 或社区包MMLib.SwaggerForOcelot。七、构建 Ocelot 的流程Building 章节索引页第三组链接指向构建流程文档building.rst本地编译 Ocelot 的步骤devprocess.rst开发流程规范是发布流程的一部分releaseprocess.rst版本发布流程。仓库同时提供Ocelot.slnx主解决方案与Ocelot.Samples.slnx示例解决方案示例项目覆盖 Basic、Configuration、GraphQL、Kubernetes、Metadata、ServiceDiscovery、ServiceFabric、WebSocket 等场景samples/。八、从文档到源码的查证路径阅读本仓库时建议按文档章节 → 对应src/模块 → 对应unit/或acceptance/测试的三步法定位实现与验证配置模型文档给出的 Schema 与 src/Configuration/File/ 下的FileRoute、FileDynamicRoute、FileAggregateRoute、FileGlobalConfiguration一一对应DI 扩展AddOcelot全家族签名在 src/DependencyInjection/ConfigurationBuilderExtensions.csMergeOcelotJson枚举与合并逻辑亦在其中管线与中间件组装顺序见 src/Middleware/OcelotPipelineExtensions.cs可运行示例Basic 示例samples/Basic/Program.cs、samples/Basic/ocelot.json可直接dotnet run验证第一节的最小路由。升级提醒生产环境升级前务必查阅 发布说明索引页特别强调并留意 24.1→25.0 的破坏性变更——FileCacheOptions与RateLimitRule旧配置段已在 25.0 移除务必迁移到CacheOptions与RateLimitOptions。赞分享API网关后端微服务【免费下载链接】Ocelot.NET API Gateway项目地址https://gitcode.com/gh_mirrors/oc/Ocelot点击查看免费下载相关推荐YI-1.5-9B-SFT性能测试中文文本生成质量与效率全面评测YI 1.5 9B SFT性能测试中文文本生成质量与效率全面评测 YI 1.5 9B SFT是基于YI 1.5 9B基础模型经过指令微调得到的中文文本生成模型Gemma 4 26B A4B IT Assistant快速入门5步掌握推测解码技术Gemma 4 26B A4B IT Assistant快速入门5步掌握推测解码技术 Gemma 4 26B A4B IT Assistant是GoogleMCP Go SDK 官方文档总览包结构、功能地图与实战导航MCP Go SDK 官方文档总览包结构、功能地图与实战导航 导读 本文以 docs/README.md https://link.gitcode.com/iMCP 服务AI Agent工具调用上一篇3大字体系列9种字重Montserrat字体家族让设计新手也能轻松打造专业排版下一篇torchtitan MoE 分片机制全解析基于配置的 EP/SP/TP 专家并行布局体系创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
DeepSpeed 1-bit Adam 训练优化:5 倍通信压缩与 3.4 倍训练加速的完整配置指南 推理引擎大模型 【免费下载链接】FlexGen Running large language models on a single GPU for throughput-oriented scenarios. 项目地址: https://gitcode.com/gh_mirrors/fl/FlexGen 点击查看 免费下载 1-bit Adam 是 DeepSpeed 中面向通信受限集群的高效训练优… · 2026/9/25 12:37:31
LangChain-模型调用六种方法 首先需要清楚什么是同步和异步
同步调用
通俗例子 你去奶茶店点单: 1. 你下单,站在柜台原地不动等待 2. 店员做完你的奶茶,交到你手上,你才能走、做别的事 整个过程你全程阻塞,不能中途刷手机、买小吃,必… · 2026/9/25 13:04:16
Blume 使用指南:用纯 Markdown 快速构建 AI 就绪的文档站点(TaoToken 配置篇) /* 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 13:04:10
昇腾Atlas 300V部署YOLOv5实战:模型转换与推理优化 1. Atlas到底是什么?先别急着把它当“显卡”我第一次接触Atlas 300V 24G时,第一反应也是打开它的规格表,试图跟手里的NVIDIA显卡做一一对应。核心数、频率、显存带宽、功耗……对着对着就发现不对劲,这东西压根不是按“显卡”的逻… · 2026/9/25 13:03:51
昇腾Atlas 300V 24G加速卡详解:从硬件定位到YOLO模型完整部署实战 前两天有人在群里问:Atlas 300V 24G是运算加速卡吗?买来能直接部署YOLO吗?我愣了一下,因为在昇腾生态里泡久了,会默认人人都知道这玩意的定位。实际上很多刚接触AI加速卡的人,连Atlas和地图集都分不清&… · 2026/9/25 13:03:45
创维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