WSS长连接下Server调用Desktop本地工具:拆分会话、执行与状态链ID
1. 从一次真实的联调卡顿说起去年年底我在做一个跨端协作工具核心场景很明确服务端需要调用用户桌面端本地安装的某个命令行工具把处理结果回传给服务端做后续编排。听起来不复杂但真动手的时候问题一个接一个冒出来。最典型的一次是服务端同时下发了三个任务桌面端返回的结果全部串了——A 任务的结果被塞进了 B 任务的回调里C 任务的状态更新覆盖了 A 任务的进度。排查了大半天最后发现根因是会话没有做隔离执行上下文和状态链 ID 全部复用了同一个全局变量。这件事让我意识到通过 WSS 让 Server 安全调用 Desktop 本地工具这个场景里真正难的不是建立连接而是连接建立之后怎么把“会话”“执行”“状态链”这三层结构拆干净。标题里说的“拆分会话、执行与状态链 ID”本质上就是在解决这个问题让每一次调用都有独立的身份、独立的生命周期、独立的追踪链路。这篇文章适合谁看如果你正在做服务端与桌面端的双向通信或者你在设计一个需要远程调度本地能力的系统再或者你只是对 WSS 长连接下的任务编排感兴趣那接下来的内容应该能帮你少走一些弯路。我会从整体设计思路讲起然后逐层拆解会话层、执行层、状态链层的实现细节最后把我在实际调试中踩过的坑和排查方法整理出来。2. 整体架构设计与拆分逻辑2.1 为什么一定要拆成三层很多人第一反应是不就是服务端发个消息桌面端执行完返回结果吗搞那么复杂干嘛。我一开始也是这么想的直到任务量上来之后各种边界情况开始暴露。举个生活化的类比。你去餐厅吃饭服务员帮你点单厨房做菜传菜员把菜端给你。如果餐厅只有一个服务员他既要记你点了什么又要去厨房盯着做还要负责端菜那同时来三桌客人他立刻就乱了。正确的做法是点单是一个独立环节会话做菜是一个独立环节执行传菜是另一个独立环节状态链。每个环节有自己的标识和状态互不干扰但又彼此关联。对应到我们的系统里会话层负责管理连接的建立、认证、心跳和生命周期。一个桌面端连上来就产生一个会话会话 ID 是这个连接的唯一身份。执行层负责管理具体的任务调用。服务端说“帮我跑一下某个本地工具”这就产生一次执行执行 ID 标识这一次具体的调用。状态链层负责追踪任务从下发到完成的全过程。状态链 ID 把一次执行中的所有状态变更串起来方便回溯和排查。这三层拆开之后每个层级的职责单一出问题的时候能快速定位是哪一层的事。会话断了就查会话层执行超时就查执行层状态对不上就查状态链层。2.2 拆分带来的核心收益拆分的收益不是理论上的好看而是实打实解决了几个痛点。第一个痛点是并发隔离。没有会话隔离的时候多个任务共用一个上下文结果就是前面说的串数据。拆开之后每个会话有独立的上下文空间会话内的执行再按执行 ID 隔离天然支持并发。第二个痛点是可追踪性。状态链 ID 的存在让每一次状态变更都有据可查。服务端下发任务时带上状态链 ID桌面端每次状态更新都回传这个 ID服务端就能把整条链路串起来。排查问题的时候拿着一个状态链 ID 就能看到这个任务从生到死的全部记录。第三个痛点是容错与重试。执行层独立之后某一次执行失败了可以单独重试这一次执行而不影响会话本身。会话还在只是这一次执行需要重新来。如果没有拆分重试就意味着整个会话重建成本高得多。2.3 通信协议选型为什么是 WSS标题里明确说了 WSS这里补充一下选型逻辑。WSS 就是基于 TLS 的 WebSocket相比普通的 WS它多了传输层的加密。对于服务端调用桌面端本地工具这个场景数据往往涉及用户本地环境的信息加密传输是基本要求。相比 HTTP 轮询WSS 的优势在于全双工。服务端可以主动推送任务给桌面端桌面端也可以主动上报状态不需要桌面端不停地问“有没有新任务”。这在任务下发频繁的场景下延迟和资源消耗都低得多。相比 SSEWSS 支持双向通信。SSE 只能服务端推客户端桌面端要上报状态还得另开 HTTP 接口多一套连接管理逻辑不划算。所以 WSS 是这个场景下比较自然的选择。当然具体到实现层面还需要考虑心跳间隔、重连策略、消息格式这些细节后面会展开。3. 会话层的核心实现细节3.1 会话建立与身份认证会话建立的第一步是连接握手。桌面端启动后主动向服务端发起 WSS 连接。连接建立后第一件事是认证。认证的方式可以灵活选择常见的有令牌认证和签名认证。令牌认证的逻辑是桌面端在连接建立后发送一条认证消息携带预先分配好的令牌。服务端校验令牌有效性通过则标记该会话为已认证否则关闭连接。令牌一般有有效期过期需要重新获取。签名认证稍微复杂一些桌面端用本地私钥对时间戳等信息签名服务端用对应公钥验签。这种方式不依赖令牌的传输安全性更高但实现成本也更高。我在实际项目里用的是令牌认证因为桌面端和服务端之间有可信的注册流程令牌可以通过注册流程安全下发。认证消息的结构大概是这样{ type: auth, token: xxxxx, clientId: desktop-001, timestamp: 1700000000 }服务端收到后校验令牌和 timestamp 的时效性通过后返回认证成功消息并分配一个会话 ID。这个会话 ID 后续所有消息都会带上作为会话层的唯一标识。注意会话 ID 的生成要保证全局唯一推荐用 UUID 或者雪花算法。不要用自增 ID因为分布式环境下自增 ID 容易冲突。3.2 心跳机制与断线检测WSS 连接建立之后如果不做心跳中间的网络设备可能会因为长时间没有数据而断开连接。而且服务端也需要知道桌面端是不是还活着。所以心跳机制是必须的。心跳的实现方式有两种一种是协议层面的 ping/pongWebSocket 协议本身支持另一种是应用层面的心跳消息。我建议用应用层面的心跳因为可控性更强可以在心跳消息里携带一些状态信息。具体做法是桌面端每隔固定时间比如 30 秒发送一条心跳消息服务端收到后更新该会话的最后活跃时间。服务端也维护一个定时器如果某个会话超过一定时间比如 90 秒没有收到心跳就判定为断线清理会话资源。{ type: heartbeat, sessionId: sess-xxxx, timestamp: 1700000000 }心跳间隔的设置需要权衡。太短会增加不必要的流量和功耗太长则断线检测不及时。30 秒是一个比较常用的值90 秒的超时阈值给了两次心跳丢失的容错空间。实操心得心跳消息不要只发时间戳可以顺带带上桌面端的当前负载信息比如正在执行的任务数。这样服务端在做任务调度的时候可以参考这个信息避免给已经繁忙的桌面端继续派活。3.3 会话生命周期管理会话的生命周期从连接建立开始到连接关闭结束。中间会经历认证、活跃、空闲、断线重连等状态。认证之前会话处于待认证状态只能接收认证消息其他消息一律拒绝。认证通过后进入活跃状态可以正常收发消息。如果一段时间没有消息往来可以标记为空闲状态但连接保持。断线之后会话进入待清理状态根据配置决定是立即清理还是保留一段时间等待重连。重连的处理需要特别注意。桌面端断线后重新连接会建立一个新的会话。如果服务端希望恢复之前的上下文就需要桌面端在重连时携带之前的会话 ID服务端根据这个 ID 找到旧会话的上下文迁移到新会话上。这个机制叫会话恢复实现起来需要服务端维护一个会话 ID 到上下文的映射并且设置合理的过期时间。{ type: reconnect, previousSessionId: sess-xxxx, token: xxxxx }服务端收到重连请求后先校验令牌然后查找 previousSessionId 对应的上下文。如果找到且未过期就把上下文绑定到新会话上返回恢复成功。如果找不到或已过期就当作全新会话处理。4. 执行层的任务调度与隔离4.1 执行 ID 的生成与绑定执行层是任务真正落地的地方。服务端下发一个任务桌面端执行这个过程需要一个执行 ID 来标识。执行 ID 的生成有两种方式服务端生成或者桌面端生成。我倾向于服务端生成因为服务端是任务的发起方由它分配 ID 更自然也方便服务端做全局的任务管理。服务端在任务消息里带上执行 ID桌面端收到后直接用这个 ID 作为本次执行的标识。{ type: task, sessionId: sess-xxxx, executionId: exec-xxxx, toolName: some-local-tool, params: { input: xxx } }执行 ID 和会话 ID 的关系是一对多。一个会话可以发起多次执行每次执行有独立的执行 ID。执行 ID 在会话内唯一即可不需要全局唯一但如果要跨会话追踪全局唯一会更方便。4.2 任务队列与并发控制桌面端收到任务后不能无限制地并发执行。本地工具的资源占用、执行时间都是不确定的如果同时跑太多任务可能把桌面端拖垮。所以需要一个任务队列来做并发控制。队列的设计要考虑几个点。首先是队列容量不能无限堆积超过容量要拒绝新任务并返回错误。其次是并发度根据桌面端的硬件配置和工具特性来设定一般 2 到 4 个并发比较稳妥。最后是优先级如果有紧急任务可以插队执行。// 简化的任务队列实现示意 class TaskQueue { constructor(concurrency) { this.concurrency concurrency; this.running 0; this.queue []; } enqueue(task) { return new Promise((resolve, reject) { this.queue.push({ task, resolve, reject }); this.process(); }); } process() { while (this.running this.concurrency this.queue.length 0) { const { task, resolve, reject } this.queue.shift(); this.running; task() .then(resolve) .catch(reject) .finally(() { this.running--; this.process(); }); } } }这个队列保证了同时执行的任务数不超过并发度超出的任务排队等待。每个任务执行完成后从队列里取下一个继续执行。注意事项队列里的任务要考虑超时。如果某个任务执行时间过长应该强制终止并返回超时错误否则会一直占用并发名额导致后续任务饿死。4.3 执行结果的回传与关联任务执行完成后桌面端需要把结果回传给服务端。回传的消息里必须带上执行 ID服务端根据执行 ID 找到对应的任务记录更新状态和结果。{ type: task-result, sessionId: sess-xxxx, executionId: exec-xxxx, status: success, output: xxx, duration: 1234 }如果执行失败status 为 erroroutput 里带上错误信息。服务端收到后根据执行 ID 更新任务状态并触发后续的编排逻辑。这里有个细节执行结果的回传可能因为网络问题丢失。所以桌面端在发送结果后应该等待服务端的确认消息。如果超时没有收到确认就重发。服务端要做幂等处理同一个执行 ID 的结果重复收到时只处理第一次后续的直接返回确认。5. 状态链 ID 的设计与追踪实现5.1 状态链 ID 的作用与生成时机状态链 ID 是贯穿整个任务生命周期的追踪标识。它和会话 ID、执行 ID 的区别在于会话 ID 标识一个连接执行 ID 标识一次调用而状态链 ID 标识一整条业务链路。为什么需要状态链 ID因为一个业务任务可能涉及多次执行。比如服务端要完成一个数据处理流程可能需要先调用桌面端的工具 A 做预处理再调用工具 B 做转换最后调用工具 C 做输出。这三次执行属于同一个业务任务应该用同一个状态链 ID 串起来。状态链 ID 由服务端在发起业务任务时生成贯穿该任务的所有执行。每次下发执行时都带上状态链 ID。桌面端每次上报状态时也带上状态链 ID。服务端就可以根据状态链 ID 把整条链路的所有事件聚合起来。{ type: task, sessionId: sess-xxxx, executionId: exec-xxxx, traceId: trace-xxxx, toolName: some-local-tool, params: {} }5.2 状态变更的事件模型状态链的核心是状态变更事件。每次任务状态发生变化就产生一个事件事件里包含状态链 ID、执行 ID、时间戳、状态类型和附加信息。状态类型一般包括created任务创建、dispatched任务下发、started开始执行、progress执行中、completed执行完成、failed执行失败、timeout执行超时。{ type: state-change, traceId: trace-xxxx, executionId: exec-xxxx, state: started, timestamp: 1700000000, detail: {} }服务端收到状态变更事件后把它追加到状态链的存储里。存储可以用内存队列加持久化也可以直接写数据库。如果对实时性要求高可以用内存存储加定期持久化如果对可靠性要求高就直接写数据库。5.3 状态链的查询与回溯状态链存储之后需要提供查询能力。最常见的查询是按状态链 ID 查整条链路的所有事件按时间排序就能看到任务的完整执行过程。SELECT * FROM state_events WHERE trace_id trace-xxxx ORDER BY timestamp ASC;这个查询结果就是任务的生命周期记录。排查问题的时候拿着这个记录能清楚地看到任务在哪个环节卡住了哪个环节耗时最长哪个环节报错了。如果要做更复杂的分析比如统计某个工具的平均执行时间可以按执行 ID 分组聚合。状态链的数据结构天然支持这种分析。实操心得状态链的事件不要只存状态类型把关键的业务信息也存进去。比如执行开始事件里存输入参数执行完成事件里存输出摘要。这样回溯的时候信息更全不用再去别的地方查。6. 三层拆分的协同与边界处理6.1 会话断开时的执行处理会话断开是一个必须处理的边界情况。如果桌面端和服务端的连接断了正在执行的任务怎么办有两种策略一种是继续执行结果暂存本地等重连后回传另一种是立即终止返回失败。选择哪种取决于业务需求。如果任务执行成本高建议继续执行并暂存结果如果任务可以快速重试立即终止更简单。我采用的是继续执行加暂存结果的策略。桌面端在检测到连接断开后不中断正在执行的任务而是把结果写到本地暂存区。重连成功后先检查暂存区把未回传的结果补发。服务端收到后按执行 ID 做幂等处理避免重复。6.2 执行超时与状态链的闭环执行超时是另一个常见问题。服务端下发任务后会设置一个超时时间。如果超过这个时间还没有收到完成或失败的状态就判定为超时。超时后服务端要做两件事一是更新状态链追加一个 timeout 事件让链路闭环二是通知桌面端取消该执行避免桌面端继续做无用功。桌面端收到取消通知后尝试终止正在执行的任务。如果任务已经无法终止比如已经进入不可中断的系统调用就标记为已取消忽略后续的结果回传。{ type: cancel, sessionId: sess-xxxx, executionId: exec-xxxx, traceId: trace-xxxx, reason: timeout }6.3 多会话下的状态链聚合一个服务端可能同时连接多个桌面端每个桌面端是一个会话。如果同一个业务任务需要在多个桌面端上执行状态链 ID 就起到了聚合的作用。服务端在发起任务时生成一个状态链 ID然后把这个任务拆分成多个子任务分别下发给不同的桌面端。每个子任务有独立的执行 ID但共享同一个状态链 ID。服务端根据状态链 ID 聚合所有子任务的状态判断整个业务任务是否完成。这种模式下状态链的查询结果会包含多个执行 ID 的事件。服务端需要按执行 ID 分组先看每个子任务的状态再汇总成整体状态。7. 常见问题与排查技巧实录7.1 消息乱序与重复的处理WSS 虽然基于 TCP理论上消息是有序的但在应用层面由于异步处理的存在消息的处理顺序可能和到达顺序不一致。比如任务下发消息先到但处理线程池满了排队等待而后到的状态查询消息先被处理了。解决思路是给消息加上序列号接收方按序列号排序后再处理。或者用单线程处理消息保证顺序但这样吞吐量会受限。重复消息的处理靠幂等。每个消息带上唯一 ID接收方记录已处理的消息 ID重复的直接忽略。消息 ID 可以用执行 ID 加状态类型加时间戳的组合来生成。7.2 状态链断裂的排查方法状态链断裂是指某个执行的状态事件没有完整上报导致链路中间缺了一段。排查的时候先确认是桌面端没发还是服务端没收到还是收到了没存。排查步骤可以这样在桌面端日志里搜索执行 ID看有没有对应的状态上报记录。如果有上报记录在服务端日志里搜索执行 ID看有没有接收记录。如果服务端有接收记录检查状态链存储看有没有写入记录。根据缺失的环节定位是网络问题、服务端处理问题还是存储问题。常见的原因是网络抖动导致消息丢失或者服务端处理时抛异常没有写入存储。前者靠重发机制解决后者靠异常捕获和补偿解决。7.3 高频问题速查表问题现象可能原因排查方向解决措施任务结果串了会话或执行未隔离检查上下文是否共用按会话 ID 和执行 ID 隔离上下文状态链缺事件消息丢失或写入失败查桌面端和服务端日志加重发机制和异常补偿执行超时无响应任务卡死或队列积压查执行日志和队列长度加超时终止和队列容量限制重连后上下文丢失会话恢复未实现或过期查会话映射和过期时间实现会话恢复并调整过期时间心跳正常但任务不通认证过期或权限问题查认证状态和权限配置重新认证或调整权限避坑技巧状态链的事件写入不要用同步阻塞的方式否则高并发下会拖慢整个处理流程。用异步写入加队列缓冲既能保证吞吐量又能通过重试保证可靠性。8. 我在实际项目中的几点体会这套三层拆分的方案我在两个项目里落地过整体效果是符合预期的。最明显的改善是排查效率。以前出了问题日志翻半天找不到头绪现在拿着状态链 ID 一查整条链路清清楚楚定位时间从小时级降到分钟级。另一个体会是拆分要适度。三层是最小可用集再细拆下去比如把执行层再拆成调度层和运行层复杂度会上升收益不一定明显。除非业务确实需要否则不建议过度设计。还有一点是关于状态链的存储。一开始我用的是内存存储简单快速但服务重启后数据就丢了。后来改成内存加定期持久化兼顾了性能和可靠性。如果对可靠性要求极高直接写数据库也行但要注意写入频率避免数据库压力过大。最后分享一个小技巧状态链的事件里可以加一个来源字段标识这个事件是桌面端上报的还是服务端生成的。这样回溯的时候能清楚看到哪些环节是桌面端的责任哪些是服务端的责任便于划分问题边界。这个字段在联调阶段特别有用能快速判断问题出在哪一侧。

相关新闻

WSS远程调用:拆分会话、执行与状态链ID的设计实践

WSS远程调用:拆分会话、执行与状态链ID的设计实践

1. 从"能跑通"到"敢上生产":为什么必须拆分会话、执行与状态链 ID很多做远程工具调用的开发者都有过这样的经历:本地写个 Demo,WebSocket 连上、发个指令、桌面端执行、结果回传,一气呵成,感觉这事…

2026/10/12 1:46:58 阅读更多 →
卫星互联网与5G对比:技术边界、场景选型与融合组网

卫星互联网与5G对比:技术边界、场景选型与融合组网

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

2026/10/12 1:46:58 阅读更多 →
嫦娥三号软着陆轨道设计与控制策略:建模、优化与仿真

嫦娥三号软着陆轨道设计与控制策略:建模、优化与仿真

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

2026/10/12 1:46:58 阅读更多 →

最新新闻

分红时代已死,资本证明时代崛起

分红时代已死,资本证明时代崛起

《分红时代已死,资本证明时代崛起》——下一轮能源周期,市场奖励的不是“投得更多”,而是“证明每一笔钱为何值得花”过去五年,能源公司靠不花钱赢得投资者;未来五年,要靠会花钱。投下去的是资本&#xff0…

2026/10/12 4:01:25 阅读更多 →
OpenUI5源码解析:DesignTime.js如何驱动可视化编辑器

OpenUI5源码解析:DesignTime.js如何驱动可视化编辑器

接触过 OpenUI5 可视化编辑器的同学,应该都对“为什么编辑器知道这个控件能拖拽、那个属性可以改”感到好奇。答案的关键,就藏在一个叫 DesignTime.js 的模块里。这是 OpenUI5 源码解析系列的第三十一篇,我们来把 DesignTime.js 完整拆开。这…

2026/10/12 4:01:25 阅读更多 →
配电网韧性提升:移动储能预布局与动态调度建模与Matlab实现

配电网韧性提升:移动储能预布局与动态调度建模与Matlab实现

1. 项目背景与核心问题剖析1.1 为什么要关注配电网韧性与移动储能先说结论:配电网韧性(Resilience)研究的本质,是在极端扰动发生后让系统"扛得住、恢复快"。传统的可靠性分析更多关注故障概率和平均停电时间&#xff0c…

2026/10/12 4:01:25 阅读更多 →
SSH 连接 VirtualBox 里的 Ubuntu

SSH 连接 VirtualBox 里的 Ubuntu

环境:VirtualBox Ubuntu 22.04.5 LTS(服务器版,镜像 ubuntu-22.04.5-live-server-amd64.iso),宿主机 Windows。初始动机 用 VirtualBox 装完 Ubuntu 服务器版后,一直盯着它自带的小黑框操作,字…

2026/10/12 4:01:25 阅读更多 →
QQ空间代码查询工具:从解压到搭建本地代码库的完整指南

QQ空间代码查询工具:从解压到搭建本地代码库的完整指南

简介:一款基于PHP编写的QQ空间代码查询工具,面向Web开发初学者、PHP爱好者以及想研究QQ空间页面结构与特效实现的用户。使用者只需输入QQ号码,程序便会向QQ空间发起请求,获取页面源码并解析出其中的HTML、CSS与JavaScript代码&…

2026/10/12 4:01:25 阅读更多 →
SonnetDB 统计聚合函数:stddev/variance/spread/median/mode

SonnetDB 统计聚合函数:stddev/variance/spread/median/mode

SonnetDB 统计聚合函数:stddev/variance/spread/median/mode SonnetDB 的统计聚合用于观察时序数据的波动、跨度和常见状态。本文介绍 stddev、variance、spread、median 和 mode,重点说明样本统计、中位数估计和类型边界。内容按 2026-10-11 当前工作树…

2026/10/12 4:00:24 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 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/11 10:45:37 阅读更多 →
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/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练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/11 14:36:54 阅读更多 →