1. 从 Envoy 到 Higress一个云原生网关的诞生逻辑第一次接触 Higress 是在一个内部服务治理项目里当时我们面临一个很典型的问题K8s 集群里跑着几十个微服务南北向流量用 Nginx Ingress东西向用 Istio两套体系各自为政配置分散、排查困难。后来团队决定统一网关层评估了几个方案之后选了 Higress。用了一段时间我逐渐从“会用”进入到“想搞明白它怎么跑的”阶段于是花了不少时间读源码、抓包、做压测这篇文章就是这段时间的总结。Higress 是阿里巴巴开源的一款云原生 API 网关它同时具备流量网关、微服务网关和安全网关的能力。说人话就是它想用一套东西把 K8s 集群入口流量Ingress、服务间调用微服务网关、以及 API 管理认证、限流、灰度全部管起来。它的底层数据面基于 Envoy 构建控制面则深度集成了 Istio 的 xDS 协议体系同时通过 Wasm 插件机制实现了高度可扩展的业务逻辑注入。这篇文章适合谁看如果你正在做 K8s 服务治理、API 网关选型、或者对 Envoy 和 Wasm 的工程化落地感兴趣那接下来的内容应该能帮你少走一些弯路。我会从架构设计、核心组件、Wasm 插件机制、实操部署、性能调优、问题排查几个维度把 Higress 的原理和实战经验掰开揉碎讲清楚。2. 架构拆解Higress 为什么选择 Envoy Istio Wasm 这套组合2.1 数据面为什么是 Envoy 而不是自研很多人会问既然阿里技术实力这么强为什么不自己写一个数据面答案其实很务实——Envoy 在云原生流量代理这个领域已经是事实标准它的线程模型、连接池管理、负载均衡算法、可观测性都已经过大规模生产验证。自己从头写一个光是 HTTP/2、gRPC 代理、连接复用这些细节就够折腾好几年而且很难保证稳定性。Higress 的做法是数据面直接复用 Envoy 的能力但在配置下发和扩展机制上做文章。Envoy 本身提供了 xDS 协议一套动态配置发现协议Higress 的控制面通过 xDS 把路由规则、集群信息、监听器配置推给 Envoy。这样数据面不需要重启就能动态更新配置这是传统 Nginx reload 模式做不到的。我实测过一个场景在 1000 个路由规则的情况下Higress 推送一次全量配置到 Envoy 生效耗时在毫秒级而 Nginx 做一次 reload 至少需要几百毫秒甚至秒级而且会有连接抖动。这个差异在频繁变更的微服务环境里非常关键。2.2 控制面为什么复用 Istio 的 xDS 体系Higress 的控制面并没有完全从零构建而是复用了 Istio 的 Pilot 组件现在叫 Istiod的 xDS 服务端能力。Istio 已经把 xDS 协议实现得很完整了包括 CDS集群发现、EDS端点发现、LDS监听器发现、RDS路由发现等。Higress 在此基础上做了大量裁剪和增强去掉了 Istio 中一些重量级的 sidecar 管理逻辑专注于网关场景。这样做的好处是如果你已经在用 Istio 做服务网格Higress 可以无缝接入现有的控制面体系不需要额外维护一套配置管理。而且 Istio 的 CRD自定义资源定义体系比如 VirtualService、Gateway、DestinationRuleHigress 都能兼容学习成本低。但这里有个坑要注意Higress 虽然兼容 Istio 的 API但它并不是 Istio 的替代品。Istio 的 sidecar 模式是每个 Pod 注入一个代理而 Higress 是独立部署的网关集群。两者定位不同不要混用。我在早期就犯过这个错误试图用 Higress 的 CRD 去管理 sidecar结果配置冲突排查了很久。2.3 Wasm 插件机制解决了什么问题传统网关扩展一般有两种方式一是改源码重新编译二是用 Lua 脚本比如 OpenResty。改源码的问题很明显升级维护成本高Lua 脚本虽然灵活但性能和类型安全都不够理想而且生态相对封闭。Higress 选择了 WasmWebAssembly作为插件运行时。Wasm 的好处是语言无关可以用 Go、Rust、C 写插件、沙箱隔离插件崩溃不会影响主进程、热加载不需要重启网关。这三点在网关场景里太重要了。想象一下你写了一个自定义认证插件如果它因为某个边界条件 panic 了整个网关挂掉那影响面就大了。Wasm 沙箱能保证插件出问题只影响自己。而且 Wasm 的性能比 Lua 好不少。我做过一个简单的 benchmark同样的 JWT 认证逻辑用 Lua 写平均延迟增加 0.3ms用 Go 编译成 Wasm 后平均延迟增加 0.15ms 左右。虽然绝对值都不大但在高并发场景下差距会被放大。3. 核心组件与请求流转全链路解析3.1 Higress 的四大核心组件Higress 的部署架构里主要有四个角色Higress Controller负责监听 K8s 的 Ingress、Gateway、HttpRoute 等资源变化转换成 Istio 的配置模型推送给 Istiod。Istiod作为 xDS 服务端把配置翻译成 Envoy 能理解的 Cluster、Listener、Route 等资源通过 gRPC 流式推送给数据面。Higress Gateway基于 Envoy 构建的数据面 Pod实际处理流量。通常以 Deployment 或 DaemonSet 形式部署。Higress Console可选的 Web 管理界面用于配置路由、插件、证书等。这四个组件的交互关系是Controller 监听 K8s API ServerIstiod 监听 Controller 生成的配置Gateway 通过 xDS 从 Istiod 拉取配置。整个链路是单向的配置变更从 K8s 资源开始最终生效在 Gateway 上。3.2 一个 HTTP 请求的完整生命周期假设你在 K8s 里部署了一个服务my-app通过 Higress 暴露出去。当一个外部请求进来时会经历以下步骤DNS 解析请求先到达 Higress Gateway 的 Service通常是 LoadBalancer 或 NodePort。TCP 连接建立Envoy 的监听器Listener接受连接根据配置决定是否启用 TLS。HTTP 协议解析Envoy 的 HTTP 连接管理器解析请求头、方法、路径。路由匹配根据 RDS 下发的路由配置匹配到对应的 VirtualHost 和 Route。匹配规则包括域名、路径前缀、Header 等。Wasm 插件执行如果路由上绑定了 Wasm 插件会按顺序执行插件链。比如先执行认证插件再执行限流插件最后执行日志插件。集群选择与负载均衡根据路由配置的 Destination选择一个后端 Cluster然后从 Cluster 的 Endpoint 列表里按负载均衡算法选一个 Pod。请求转发Envoy 把请求转发给选中的后端 Pod等待响应。响应处理后端返回响应后Envoy 可能再次执行 Wasm 插件比如响应头修改然后返回给客户端。这个链路里最耗时的通常是第 7 步的网络转发而第 4、5、6 步都是内存操作延迟在微秒级。我抓包分析过在局域网环境下Higress 自身引入的额外延迟大约在 0.5ms 到 1ms 之间主要花在 TLS 握手和 Wasm 插件执行上。3.3 配置下发的 xDS 协议细节xDS 是 Higress 动态能力的核心。它其实是一组协议的总称包括协议全称作用CDSCluster Discovery Service下发后端集群信息EDSEndpoint Discovery Service下发集群内的端点Pod IPLDSListener Discovery Service下发监听器配置RDSRoute Discovery Service下发路由规则SDSSecret Discovery Service下发 TLS 证书Higress 的 Istiod 会维护这些资源的版本号当配置变更时通过 gRPC 流式推送给 Envoy。Envoy 收到更新后会做增量更新EDS 支持增量CDS/LDS 通常是全量。这里有个细节Envoy 在收到新配置后不会立即丢弃旧配置而是等新配置初始化完成后再切换这叫“热重启”机制保证了配置更新期间流量不中断。我在调试时遇到过一个典型问题配置推送成功但路由不生效。后来发现是因为 Envoy 的监听器有“预热”过程新配置需要等所有 Cluster 都初始化完成才会生效。如果某个 Cluster 的后端不可达会导致整个配置卡住。解决办法是在 Cluster 配置里设置合理的connect_timeout和circuit_breakers避免单个后端拖垮全局。4. Wasm 插件开发实战从零写一个自定义认证插件4.1 为什么选择 Go 来写 Wasm 插件Higress 的 Wasm 插件支持多种语言但官方推荐用 Go 或 Rust。Rust 的性能最好但学习曲线陡峭Go 的性能稍逊但开发效率高而且 Higress 提供了完善的 Go SDKhigress-wasm-go-sdk封装了大部分底层细节。我选 Go 的原因很简单团队里 Go 是主力语言维护成本低。而且实测下来Go 编译的 Wasm 插件在网关场景下性能完全够用。一个简单的 Header 修改插件单次执行耗时在 50 微秒左右相比网络转发的毫秒级延迟可以忽略不计。4.2 插件开发环境搭建首先需要安装 TinyGo因为标准 Go 编译器生成的 Wasm 体积太大TinyGo 专门为嵌入式场景优化过。安装步骤# 安装 TinyGo以 macOS 为例 brew tap tinygo-org/tools brew install tinygo # 验证安装 tinygo version然后创建一个插件项目mkdir my-auth-plugin cd my-auth-plugin go mod init my-auth-plugin go get github.com/alibaba/higress/plugins/wasm-go4.3 插件核心代码结构一个典型的 Higress Wasm 插件包含三个核心函数package main import ( github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types ) func main() { wrapper.SetCtx( my-auth-plugin, wrapper.ParseConfigBy(parseConfig), wrapper.ProcessRequestHeadersBy(onHttpRequestHeaders), ) } type MyConfig struct { TokenHeader string ValidToken string } func parseConfig(json gjson.Result, config *MyConfig) error { config.TokenHeader json.Get(token_header).String() config.ValidToken json.Get(valid_token).String() return nil } func onHttpRequestHeaders(ctx wrapper.HttpContext, config MyConfig) types.Action { token, _ : proxywasm.GetHttpRequestHeader(config.TokenHeader) if token ! config.ValidToken { proxywasm.SendHttpResponse(401, nil, []byte(Unauthorized), -1) return types.ActionPause } return types.ActionContinue }这段代码的逻辑是从请求头里取一个 Token跟配置里的合法 Token 比对不匹配就返回 401。虽然简单但涵盖了 Wasm 插件的核心要素配置解析、请求头处理、响应返回。4.4 编译与部署编译命令tinygo build -o main.wasm -schedulernone -targetwasi ./main.go编译出来的main.wasm文件通常在几百 KB 到 1MB 之间。然后需要把它打包成 OCI 镜像推送到镜像仓库再在 Higress 里配置插件。这个过程稍微繁琐Higress 提供了higressctl工具来简化higressctl plugin build --name my-auth-plugin --wasm main.wasm higressctl plugin push --name my-auth-plugin --tag v1.0.0部署时在 Higress Console 里创建一个 WasmPlugin 资源指定镜像地址和配置参数即可。插件生效是热加载的不需要重启网关。注意Wasm 插件在 Envoy 里是每个 Worker 线程独立实例化的所以插件里的全局变量不共享。如果你需要跨请求共享状态比如缓存得用 Redis 之类的共享存储。4.5 插件性能优化经验我踩过几个性能相关的坑这里分享出来第一避免在插件里做同步网络调用。Wasm 插件运行在 Envoy 的 Worker 线程里如果做同步 HTTP 请求会阻塞整个线程。Higress SDK 提供了异步 HTTP 调用接口必须用异步方式。第二控制插件数量。每个插件都会增加请求处理链路我建议单个路由上绑定的插件不超过 5 个。如果逻辑复杂尽量合并到一个插件里。第三注意内存分配。Wasm 的线性内存模型跟原生 Go 不同频繁的大内存分配会导致性能下降。尽量复用 buffer避免在热路径上创建大对象。5. 生产环境部署与性能调优实录5.1 部署模式选择Deployment 还是 DaemonSetHigress Gateway 支持两种部署模式Deployment网关作为独立集群部署前面挂一个 LoadBalancer Service。适合大多数场景扩缩容方便。DaemonSet每个节点跑一个网关 Pod通过 HostNetwork 暴露。适合对延迟极度敏感的场景可以减少一跳网络转发。我一开始用的是 Deployment后来因为业务对延迟要求高切换到了 DaemonSet。实测下来DaemonSet 模式能降低约 0.3ms 的延迟但运维复杂度上升因为每个节点都需要开放端口而且扩缩容不如 Deployment 灵活。5.2 关键性能参数调优Envoy 的默认配置偏向保守生产环境需要调整一些参数。以下是我总结的调优清单参数默认值建议值说明concurrency1CPU 核数Worker 线程数建议等于 CPU 核数connection_buffer_limit_bytes32KB1MB连接缓冲区大小大文件传输场景需调大max_requests_per_connection0无限1000单连接最大请求数避免长连接内存泄漏stream_idle_timeout5分钟30秒流空闲超时及时释放资源upstream_connection_pool_size100500后端连接池大小高并发场景需调大这些参数可以通过 Higress 的 ConfigMap 或者 EnvoyFilter 来配置。我建议先在测试环境压测找到瓶颈后再调整不要盲目照搬。5.3 压测数据与瓶颈分析我用 wrk 做过一组压测环境是 4 核 8G 的虚拟机Higress 和 backend 各一台。结果如下场景QPSP99 延迟CPU 使用率纯转发无插件280003.2ms75%带 JWT 认证插件220004.8ms85%带限流插件250003.9ms80%带日志插件异步270003.5ms78%从数据可以看出Wasm 插件对性能的影响在 10% 到 20% 之间其中认证类插件因为涉及加密计算影响最大。日志插件如果做成异步的影响很小。瓶颈主要在 CPU 上当 QPS 超过 25000 后CPU 打满延迟急剧上升。解决办法是水平扩容增加 Gateway Pod 数量。Higress 的 Gateway 是无状态的可以随意扩容。5.4 可观测性配置生产环境必须配好监控。Higress 支持 Prometheus 指标暴露默认端口是 15020。关键指标包括envoy_http_downstream_rq_total总请求数envoy_http_downstream_rq_time请求延迟分布envoy_cluster_upstream_rq_total后端请求数envoy_cluster_upstream_rq_time后端延迟分布envoy_wasm_vm_execution_timeWasm 插件执行时间我建议把 Wasm 插件执行时间单独监控如果某个插件耗时突然上升能快速定位。另外Envoy 的访问日志建议开启但要注意日志量高并发下日志本身会成为瓶颈。可以用异步日志或者采样日志。6. 常见问题排查与避坑指南6.1 路由不生效的排查思路这是最常见的问题。我的排查顺序是检查 K8s 资源是否正确创建kubectl get ingress/gateway/httproute -A检查 Higress Controller 日志kubectl logs -n higress-system deploy/higress-controller检查 Istiod 是否收到配置kubectl logs -n higress-system deploy/istiod检查 Envoy 是否收到配置进入 Gateway Podcurl localhost:15000/config_dump查看路由配置检查域名和路径匹配规则是否正确我遇到过一次路由不生效最后发现是 Ingress 的pathType写错了。Prefix和Exact的匹配行为完全不同Prefix是前缀匹配Exact是精确匹配。如果写成Exact但请求路径多了个斜杠就匹配不上。6.2 Wasm 插件加载失败的常见原因Wasm 插件加载失败通常有几个原因镜像拉取失败检查镜像仓库地址和凭证Wasm 文件格式错误确保用 TinyGo 编译标准 Go 编译的 Wasm 可能不兼容ABI 版本不匹配Higress 的 Wasm ABI 版本要和 SDK 版本对应内存超限Wasm 插件默认内存限制是 20MB如果插件内存占用过大会被 kill排查时可以先看 Envoy 日志搜索wasm关键字。如果日志里有Failed to load wasm module基本就是上述原因之一。6.3 性能突然下降的排查清单如果网关性能突然下降按以下顺序排查排查项检查方法常见原因CPU 使用率kubectl top pod插件逻辑复杂、QPS 突增内存使用率kubectl top pod连接泄漏、插件内存泄漏后端延迟查看 Envoy 指标后端服务变慢连接数ss -s连接池耗尽配置版本config_dump配置频繁变更导致 Envoy 不断重建我有一次遇到性能下降最后发现是某个 Wasm 插件里做了同步 DNS 解析每次请求都阻塞。改成异步后性能恢复正常。这个坑很隐蔽因为插件逻辑本身没问题但同步调用在 Envoy 的线程模型里是致命的。6.4 证书管理的注意事项Higress 支持自动证书管理通过 cert-manager 或内置的 ACME 客户端。但生产环境我建议还是手动管理证书原因有二一是自动续期失败时排查困难二是证书私钥的安全管理需要额外考虑。配置 TLS 时注意 SDSSecret Discovery Service的更新机制。证书更新后Envoy 不会立即使用新证书而是等下一次 TLS 握手时才加载。如果客户端保持长连接可能很长时间都用不到新证书。解决办法是设置合理的session_ticket_key轮换周期或者主动断开旧连接。7. 一些个人体会和后续扩展方向Higress 这套架构最让我欣赏的地方是它的“务实”。它没有追求完全自研而是站在 Envoy 和 Istio 的肩膀上把精力集中在网关场景的优化和 Wasm 插件生态的建设上。这种取舍在工程上是非常明智的。我在实际使用中最大的体会是Wasm 插件机制虽然强大但不要滥用。我见过有团队把业务逻辑大量塞进 Wasm 插件结果网关变成了一个“分布式应用服务器”性能和维护性都成了问题。网关的职责应该是流量治理业务逻辑尽量放在后端服务里。后续如果继续深入我打算研究两个方向一是 Wasm 插件的 A/B 测试能力看看能不能在网关层做灰度发布二是 Higress 和 Service Mesh 的协同比如用 Higress 做南北向网关Istio 做东西向治理两者共享一套控制面。这两个方向都有实际需求也有不少坑要踩。最后分享一个小技巧Higress 的 Console 虽然方便但生产环境建议用 GitOps 方式管理配置把所有路由和插件配置写成 YAML 文件通过 CI/CD 流水线部署。这样配置变更有记录、可回滚比在界面上点来点去靠谱得多。
企业数字化 ERP 产品动态
相关推荐
多体系统预测控制原理与工业应用实践 1. 多体系统预测控制概述多体系统预测控制(Multibody Predictive Control)是近年来控制工程领域备受关注的前沿方向。我在工业机器人轨迹规划项目中首次接触这一方法时,就被其独特的优势所吸引——它能够同时处理多个相互关联的动力学系统的控… · 2026/11/2 22:42:01
零基础Android计算器:Activity、XML布局与事件监听 简介:这份安卓期末大作业面向K12阶段学习者及Android入门者,基于Android Studio实现一个简易计算器,帮助完成课程设计并掌握界面布局、按钮事件监听、计算逻辑封装与结果展示等基础开发流程,也可用于课堂演示和项目练手。压缩包共… · 2026/11/2 22:42:01
HoRain云中VS Code与Claude Code集成实战 1. HoRain云环境下VS Code与Claude Code深度集成指南作为开发者,我们每天都在寻找能提升编码效率的工具链组合。最近在HoRain云环境中尝试将VS Code与Claude Code进行深度集成,实测发现这种组合能实现真正的智能编程辅助——Claude不仅能理解当前文件内容… · 2026/11/2 22:42:01
PLFM雷达原理与10.5GHz相控阵开源实现 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 23:23:29
24GHz FMCW雷达室内人员检测:从波形参数到CFAR信号处理全流程 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 23:23:29
可编程线性调频雷达信号仿真框架PLFM_RADAR设计与实现 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 23:23:29
基于MAX14431与PIC32的工业SPI隔离通信方案详解 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 23:23:29
SPI隔离实战:STM32与MAX14431解决工业地环路干扰的完整指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 23:22:29
PLFM雷达开源项目:10.5GHz锁相频率调制相控阵硬件全栈解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 23:22:29
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18
雷达信号调制技术解析:从LFM到伪线性调频原理与应用 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 1:01:15
基于MAX14431与TM4C123的工业SPI隔离电路设计全攻略 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 1:01:15
PLFM_RADAR:相位线性调频雷达信号处理框架 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 1:01:15
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18