Hyperf WebSocket Server 完整实战指南:从服务注册、握手路由到跨进程消息推送
后端Web框架微服务RPC框架异步编程【免费下载链接】hyperf A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.项目地址https://gitcode.com/hyperf/hyperf点击查看免费下载Hyperf 通过hyperf/websocket-server组件为 WebSocket 提供了完整的封装使开发者能够在协程框架内以近乎 HTTP 服务的开发体验快速搭建 WebSocket 应用。本文将以官方文档为骨架结合仓库源码从安装、服务配置、路由与中间件、控制器编写、连接级上下文、跨 Worker 消息推送以及 HTTP/WebSocket 混合监听等方面带你完整掌握在 Hyperf 中构建 WebSocket 服务的全过程。组件简介与安装hyperf/websocket-server是 Hyperf 官方提供的 WebSocket Server 封装组件。它复用了 Hyperf 的依赖注入DI、中间件、路由与异常处理体系将 Swoole/Swow 底层的 WebSocket 事件回调收敛为与 HTTP 控制器风格一致的编程模型。其核心入口类Hyperf\WebSocketServer\Server实现了OnHandShakeInterface、OnMessageInterface、OnCloseInterface三个契约见 src/websocket-server/src/Server.php。安装组件composer require hyperf/websocket-server安装完成后即可在config/autoload/server.php中注册 WebSocket 服务。服务端配置注册 WebSocket Server编辑config/autoload/server.php在servers数组中追加一个类型为Server::SERVER_WEBSOCKET的服务?php return [ servers [ [ name ws, type Server::SERVER_WEBSOCKET, host 0.0.0.0, port 9502, sock_type SWOOLE_SOCK_TCP, callbacks [ Event::ON_HAND_SHAKE [Hyperf\WebSocketServer\Server::class, onHandShake], Event::ON_MESSAGE [Hyperf\WebSocketServer\Server::class, onMessage], Event::ON_CLOSE [Hyperf\WebSocketServer\Server::class, onClose], ], ], ], ];配置项说明name服务名称用于后续路由、中间件配置中对该服务进行定位type服务类型WebSocket 服务必须使用Server::SERVER_WEBSOCKEThost/port监听地址与端口示例中监听0.0.0.0:9502sock_type套接字类型TCP 服务使用SWOOLE_SOCK_TCPcallbacks事件回调映射将握手、消息、关闭三个事件分别绑定到Hyperf\WebSocketServer\Server的onHandShake、onMessage、onClose方法。从源码看onHandShakesrc/websocket-server/src/Server.php#L118-L186是 WebSocket 请求的入口它会先通过Security校验sec-websocket-key正则#^[/0-9A-Za-z]{21}[AQgw]$#且 base64 解码后长度必须为 16见 src/websocket-server/src/Security.php随后交由CoreMiddleware完成路由分发并利用FdCollector记录「fd → 控制器类」的映射关系src/websocket-server/src/Collector/FdCollector.php为后续onMessage/onClose找到对应的处理实例。路由配置目前 WebSocket 路由仅支持配置文件方式注解模式将在未来版本提供。在config/routes.php中通过Router::addServer()为名为ws的 Server 添加路由。这里的ws必须与config/autoload/server.php中 WebSocket 服务的name值保持一致?php Router::addServer(ws, function () { Router::get(/, App\Controller\WebSocketController); });Router::get的第一个参数是路径第二个参数是该路径对应的控制器类。由于 Hyperf 的 WebSocket 服务复用 HTTP 路由体系握手阶段即完成路由匹配匹配失败会抛出WebSocketHandShakeException对应源码 src/websocket-server/src/CoreMiddleware.php#L30-L35 中对「Router not exist.」的处理。中间件配置在config/autoload/middlewares.php中以 Server 的name为键配置该服务的全局中间件?php return [ ws [ yourMiddleware::class ] ];同样地ws取决于你在config/autoload/server.php中配置的 WebSocket 服务名。从Server::initCoreMiddlewaresrc/websocket-server/src/Server.php#L79-L89可以看到中间件读取自middlewares.serverName异常处理器默认使用WebSocketExceptionHandler::class也可通过exceptions.handler.serverName覆盖配置。握手阶段会将全局中间件与路由级中间件合并后统一执行。编写 WebSocket 控制器控制器同时实现OnMessageInterface、OnOpenInterface、OnCloseInterface三个接口即可分别处理消息、连接建立与连接关闭?php declare(strict_types1); namespace App\Controller; use Hyperf\Contract\OnCloseInterface; use Hyperf\Contract\OnMessageInterface; use Hyperf\Contract\OnOpenInterface; use Hyperf\Engine\WebSocket\Frame; use Hyperf\Engine\WebSocket\Response; use Hyperf\WebSocketServer\Constant\Opcode; use Swoole\Server; use Swoole\WebSocket\Server as WebSocketServer; class WebSocketController implements OnMessageInterface, OnOpenInterface, OnCloseInterface { public function onMessage($server, $frame): void { $response (new Response($server))-init($frame); if($frame-opcode Opcode::PING) { // 如果使用 Coroutine Server识别到 PING 帧后需要手动处理并返回 PONG 帧。 // 对于异步风格 Server可以直接通过 Swoole 配置处理。 $response-push(new Frame(opcode: Opcode::PONG)); return; } $response-push(new Frame(payloadData: Recv: . $frame-data)); } public function onClose($server, int $fd, int $reactorId): void { var_dump(closed); } public function onOpen($server, $request): void { $response (new Response($server))-init($request); $response-push(new Frame(payloadData: Opened)); } }关键点说明消息收发onMessage中通过(new Response($server))-init($frame)获取当前连接的响应对象再调用push(new Frame(...))向客户端回传数据Frame支持命名参数构造payloadData为数据内容、opcode为帧类型。PING/PONG 心跳代码对Opcode::PING进行了显式识别并返回Opcode::PONG帧。注释特别提醒使用 Coroutine Server 时必须在应用层手动应答 PING异步风格 Server 则可通过 Swoole 配置自动处理。帧类型常量Opcode类src/websocket-server/src/Constant/Opcode.php定义了CONTINUATION(0x0)、TEXT(0x1)、BINARY(0x2)、CLOSE(0x8)、PING(0x9)、PONG(0xA)六种标准操作码可用于判断文本、二进制、关闭、心跳等帧。打开与关闭onOpen在握手成功后触发可用于下发欢迎信息或初始化状态onClose收到连接关闭事件可用于资源清理。从源码看Server::onMessagesrc/websocket-server/src/Server.php#L188-L214会先从FdCollector取出该 fd 对应的控制器类并实例化再校验其是否实现OnMessageInterface然后调用onMessageonClosesrc/websocket-server/src/Server.php#L216-L240则在defer中清理FdCollector与连接上下文保证异常情况下也能释放资源。启动服务与验证完成上述配置后启动服务$ php bin/hyperf.php start [INFO] Worker#0 started. [INFO] WebSocket Server listening at 0.0.0.0:9502 [INFO] HTTP Server listening at 0.0.0.0:9501可以看到 WebSocket Server 已在9502端口运行即可使用任意 WebSocket Client 连接并传输数据。! 当 HTTP Server9501与 WebSocket Server9502同时监听时WebSocket Client 通过这两个端口均能连接成功即连接ws://0.0.0.0:9501与ws://0.0.0.0:9502都会握手成功。这是因为Swoole\WebSocket\Server继承自Swoole\Http\Server天然具备 HTTP 能力。因此你也可以利用 HTTP 请求来触发 WebSocket 推送具体可参考 Swoole 文档中onRequest回调部分。如果你需要禁用 HTTP 服务的 WebSocket 协议能力可以在config/autoload/server.php中为http服务添加open_websocket_protocol配置项?php return [ // 该文件的其他配置已省略 servers [ [ name http, type Server::SERVER_HTTP, host 0.0.0.0, port 9501, sock_type SWOOLE_SOCK_TCP, callbacks [ Event::ON_REQUEST [Hyperf\HttpServer\Server::class, onRequest], ], settings [ open_websocket_protocol false, ] ], ] ];连接级上下文ContextWebSocket 服务的onOpen、onMessage、onClose回调并不在同一个协程中触发因此不能直接依赖协程上下文coroutine context来跨回调保存状态。hyperf/websocket-server为此提供了连接级connection-level上下文Hyperf\WebSocketServer\Context其 API 与协程上下文完全一致?php declare(strict_types1); namespace App\Controller; use Hyperf\Contract\OnMessageInterface; use Hyperf\Contract\OnOpenInterface; use Hyperf\Engine\WebSocket\Frame; use Hyperf\Engine\WebSocket\Response; use Hyperf\WebSocketServer\Context; use Swoole\WebSocket\Server as WebSocketServer; class WebSocketController implements OnMessageInterface, OnOpenInterface { public function onMessage($server, $frame): void { $response (new Response($server))-init($frame); $response-push(new Frame(payloadData: Username: . Context::get(username))); } public function onOpen($server, $request): void { Context::set(username, $request-cookie[username]); } }上面的示例中onOpen将客户端 Cookie 中的用户名写入连接上下文onMessage中即可读取到该值实现了跨回调的会话数据共享。从源码src/websocket-server/src/Context.php可以看到其实现机制Context内部以静态数组存储所有数据以fd作为一级键、以id作为二级键进行读写如sprintf(%d.%s, $fd, $id)从而将数据与具体连接绑定fd由协程上下文中的Context::FD即ws.fd提供该值在Server::onHandShake、onMessage、onClose中都会通过Context::set(WsContext::FD, $fd)写入见 src/websocket-server/src/Server.php#L123、#L195、#L225。Context提供的方法包括set($id, $value)写入数据get($id, $default null, $fd null)读取数据支持指定 fdhas($id, $fd null)判断是否存在destroy($id)销毁单个键release(?int $fd null)释放整个连接的全部数据copy($fromFd, $keys [])将指定连接的数据复制到当前连接可选复制部分键override($id, Closure $closure)/getOrSet($id, $value)便捷的读改写工具方法。这些能力均有对应的单元测试覆盖见 src/websocket-server/tests/ContextTest.php包括并发场景下的copy行为验证。多服务部署Nginx 负载均衡当 WebSocket 服务需要水平扩展时可通过 Nginx 对多个 WebSocket Server 实例做反向代理与负载均衡。因为 WebSocket 是基于 Upgrade 的长连接协议需要显式设置 Upgrade 相关的请求头# /etc/nginx/conf.d/ng_socketio.conf # Multiple ws servers upstream io_nodes { server ws1:9502; server ws2:9502; } server { listen 9502; # server_name your.socket.io; location / { proxy_set_header Upgrade websocket; proxy_set_header Connection upgrade; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # proxy_set_header Host $host; # proxy_http_version 1.1; # Forward ke multiple ws servers proxy_pass http://io_nodes; } }其中upstream中按需列出多个 WebSocket 服务节点示例为ws1:9502与ws2:9502proxy_set_header Upgrade websocket与proxy_set_header Connection upgrade是 WebSocket 代理的关键配置缺少它们会导致握手失败。跨进程消息推送Sender当需要在 HTTP 服务或其他服务中主动向某个 WebSocket 连接推送数据或关闭连接时可以直接使用Hyperf\WebSocketServer\Sender。工作原理Sender会先判断目标fd是否归属于当前 Worker。若属于当前 Worker则直接通过 Swoole Server 发送数据若不属于则通过PipeMessage将消息广播给除自己以外的所有 Worker由持有该fd的 Worker 完成实际发送。Sender提供两个核心 APIpush推送数据与disconnect断开连接在 HTTP 控制器中的典型用法如下?php declare(strict_types1); namespace App\Controller; use Hyperf\Di\Annotation\Inject; use Hyperf\HttpServer\Annotation\AutoController; use Hyperf\WebSocketServer\Sender; use function Hyperf\Coroutine\go; #[AutoController] class ServerController { #[Inject] protected Sender $sender; public function close(int $fd) { go(function () use ($fd) { sleep(1); $this-sender-disconnect($fd); }); return ; } public function send(int $fd) { $this-sender-push($fd, Hello World.); return ; } }上述示例分别演示了/server/close/{fd}在延迟 1 秒后断开指定连接go创建协程避免阻塞请求以及/server/send/{fd}立即向指定 fd 推送Hello World.文本。从源码src/websocket-server/src/Sender.php可以进一步理解其实现细节连接状态校验check($fd)通过connection_info($fd)获取连接信息仅当websocket_status WEBSOCKET_STATUS_ACTIVE时认为连接可写src/websocket-server/src/Sender.php#L128-L137相关行为在 src/websocket-server/tests/SenderTest.php 的testSenderCheck中有完整测试跨 Worker 广播sendPipeMessage()遍历worker_num - 1个 Worker向除自己外的每个 Worker 发送SenderPipeMessagesrc/websocket-server/src/Sender.php#L178-L188消息接收端OnPipeMessageListenersrc/websocket-server/src/Listener/OnPipeMessageListener.php监听OnPipeMessage事件识别SenderPipeMessage后由收到消息的 Worker 执行proxy()完成发送Worker 身份绑定InitSenderListenersrc/websocket-server/src/Listener/InitSenderListener.php在AfterWorkerStart事件中为Sender注入当前workerId这是跨进程定位与广播的基础协程风格 Server 适配当server.type为CoroutineServer或SwowServer时Sender切换为基于responses映射的直接发送模式无需跨进程广播。在 WebSocket 服务中处理 HTTP 请求除了通过端口将 HTTP 服务与 WebSocket 服务分离还可以让 WebSocket 服务同时监听 HTTP 请求。由于server.servers.*.callbacks中的配置项是单例singleton的因此需要先在dependencies中配置独立的实例?php return [ HttpServer Hyperf\HttpServer\Server::class, ];然后在config/autoload/server.php中为ws服务的callbacks添加Event::ON_REQUEST回调无关配置已省略?php declare(strict_types1); use Hyperf\Server\Event; use Hyperf\Server\Server; return [ mode SWOOLE_BASE, servers [ [ name ws, type Server::SERVER_WEBSOCKET, host 0.0.0.0, port 9502, sock_type SWOOLE_SOCK_TCP, callbacks [ Event::ON_REQUEST [HttpServer, onRequest], Event::ON_HAND_SHAKE [Hyperf\WebSocketServer\Server::class, onHandShake], Event::ON_MESSAGE [Hyperf\WebSocketServer\Server::class, onMessage], Event::ON_CLOSE [Hyperf\WebSocketServer\Server::class, onClose], ], ], ], ];最后即可在ws服务上添加 HTTP 路由。这样同一端口既能提供 WebSocket 长连接服务也能响应普通 HTTP 请求便于在单端口场景下实现「HTTP 触发推送」的架构。总结Hyperf 的 WebSocket Server 组件将握手校验、路由分发、中间件、异常处理、连接级上下文与跨 Worker 消息发送等复杂逻辑封装在Server、CoreMiddleware、Context、Sender等类中组件全部源码位于 src/websocket-server/src开发者只需关注控制器逻辑本身。掌握本文的服务注册、路由与中间件绑定、PING/PONG 心跳、连接上下文与 Sender 跨进程推送即可在生产中构建稳定可扩展的 WebSocket 应用并平滑接入 Nginx 负载均衡与多 Worker 部署架构。赞分享后端Web框架微服务RPC框架异步编程【免费下载链接】hyperf A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.项目地址https://gitcode.com/hyperf/hyperf点击查看免费下载相关推荐Hyperf WebSocket Server 实战指南从安装配置到跨进程消息推送的完整实现Hyperf WebSocket Server 实战指南从安装配置到跨进程消息推送的完整实现 导读 Hyperf 框架对 Swoole/Swow 的 WebS后端Web框架微服务RPC框架异步编程Hyperf WebSocket Server 实战指南从服务搭建到连接级上下文与跨 Worker 消息发送Hyperf WebSocket Server 实战指南从服务搭建到连接级上下文与跨 Worker 消息发送 Hyperf 官方文档 docs/zh cn/w后端微服务Hyperf WebSocket Server 实战指南从安装配置到连接上下文与跨 Worker 消息推送Hyperf WebSocket Server 实战指南从安装配置到连接上下文与跨 Worker 消息推送 导读 本文是 Hyperf 框架中 hyperf/后端Web框架微服务RPC框架异步编程上一篇如何将AITemplate与Jupyter集成交互式推理优化开发终极指南下一篇UZI-Skill 多平台安装完全指南Claude Code、Codex、Cursor、Gemini CLI 6种Agent一键配置创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

ESP32-C6自托管温度告警系统:从传感器到MQTT全链路实战

ESP32-C6自托管温度告警系统:从传感器到MQTT全链路实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 2:04:22 阅读更多 →
JavaWeb考试系统实战:事务一致性与高并发设计

JavaWeb考试系统实战:事务一致性与高并发设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 2:04:22 阅读更多 →
前端未死,边界已变:从支付宝 AFX 打散看 2026 前端工程师的 AI 全栈转型与 TaoToken 统一 Key 通道

前端未死,边界已变:从支付宝 AFX 打散看 2026 前端工程师的 AI 全栈转型与 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/10/9 2:04:21 阅读更多 →

最新新闻

SHA1算法的各种密码分析方法全面盘点

SHA1算法的各种密码分析方法全面盘点

SHA1算法的各种密码分析方法全面盘点SHA-1(安全散列算法1)是由NSA设计、NIST于1995年发布的160位密码杂凑函数。基于Merkle-Damgrd迭代结构,将任意长度消息分为512位块,通过压缩函数依次处理。理论上,SHA-1应具备160位…

2026/10/9 2:34:38 阅读更多 →
Python 数据挖掘实战项目:电商用户行为分析(聚类分群、流失预测与关联规则)

Python 数据挖掘实战项目:电商用户行为分析(聚类分群、流失预测与关联规则)

Python 数据挖掘实战项目:电商用户行为分析(聚类分群、流失预测与关联规则) 数据挖掘课程设计与竞赛入门的共同痛点是「没有真实数据可练」。本工程内置一个带真实行为规律的订单数据生成器(5000 用户 / 约 3 万条订单&#xff0…

2026/10/9 2:34:38 阅读更多 →
Java 异常处理实战案例集:50 个高频异常的现象、根因、修复与预防

Java 异常处理实战案例集:50 个高频异常的现象、根因、修复与预防

Java 异常处理实战案例集:50 个高频异常的现象、根因、修复与预防 异常处理是 Java 面试与答辩的必考题,但多数教程只讲语法不讲「为什么会炸」。这套案例集把 50 个高频异常按 8 大家族归类,每个案例固定四段式:现象&#xff08…

2026/10/9 2:34:38 阅读更多 →
SaaS「现金陷阱」全解析:EnterpriseCRM 案例教你如何识破 5:1 LTV:CAC 的假象(Product-Manager-Skills 实战拆解)

SaaS「现金陷阱」全解析:EnterpriseCRM 案例教你如何识破 5:1 LTV:CAC 的假象(Product-Manager-Skills 实战拆解)

AI 技能AI 插件 【免费下载链接】Product-Manager-Skills Product Management skills framework built on battle-tested methods for Claude Code, Cowork, Codex, and AI agents. 项目地址: https://gitcode.com/gh_mirrors/pr/Product-Manager-Skills 点击查看 免…

2026/10/9 2:34:38 阅读更多 →
互联网消费金融资金合作模式全解析:助贷、联合贷、ABS与信托通道选型指南

互联网消费金融资金合作模式全解析:助贷、联合贷、ABS与信托通道选型指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 2:34:38 阅读更多 →
Loop 径向菜单窗口管理完整指南:按住一个键,窗口就去哪

Loop 径向菜单窗口管理完整指南:按住一个键,窗口就去哪

Loop 径向菜单窗口管理完整指南:按住一个键,窗口就去哪 【免费下载链接】Loop Window management made elegant. 项目地址: https://gitcode.com/GitHub_Trending/lo/Loop 手要拖窗口之前 光标悬在窗口标题栏上,手指刚要往下拽&#…

2026/10/9 2:33:38 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 10:10:36 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式: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/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 13:34:55 阅读更多 →