PHP对接海关申报:报文结构、签名流程与异步回执全解析
简介179号海关公告官方接口对接通常面临加签、验签、定时同步等多重环节对外贸企业的IT人员尤其具有挑战性。这套PHP接入示例包面向外贸系统开发人员以服务器端脚本和客户端定时任务为主线完整演示了从HTTP请求、参数加签、服务端验签到公告数据解析的整个闭环。压缩包共6个文件涵盖2个PHP脚本服务端与客户端、2个JS工具文件、1个HTML触发页面及1份DOCX说明文档整体仅156KB轻量但链路完整。目前已有961人学习下载。借助包内提供的签名生成工具和加签验证逻辑开发者可直接复用核心代码快速接入179号海关公告接口省去自行摸索签名规则与定时轮询的耗时。1. 179号海关公告接入为什么PHP团队只能硬啃XML、签名与回执第一次接到179号海关申报相关的对接需求时我以为只是一次普通的HTTP接口调用。真正开始做才发现海关申报接入和日常开发完全不是一回事报文是固定结构的XML字段名不按驼峰也不按下划线签名用的不是JWT而是证书体系成功提交之后还不一定马上能拿到结果得靠异步回执确认。整个链路对PHP开发者来说就是一个黑匣子报文格式错、时间不对、签名算法不匹配任何一种情况都会让申报被拒收而且问题不一定当场暴露。这篇文章适合要接海关申报、要处理回执状态映射的PHP工程师我会从报文结构、签名流程、代码落地、踩坑记录到上线前的验证手段把整个接入过程拆开讲清楚。2. 报文结构与签名流程两个必须提前锁死的边界条件海关申报的报文不是“传一个JSON字段过去就行”的模式它有固定的报文根节点、业务主体、签名节点三层结构。在动手写任何PHP代码之前我建议你先花时间把两个边界条件定下来报文怎么组织、签名怎么计算。这两个问题不定清楚后续所有代码都是白写。2.1 从申报单到报文先把三块结构拆开海关申报报文的主体结构常见做法是根节点下面挂三块内容报文路由信息、业务单证数据、附加材料。路由信息负责告诉对方这条报文是谁发的、发给谁、消息类型是什么业务单证数据是核心装着具体的申报字段附加材料用于上传随附单证或附件清单。这种分层结构的好处是不管业务类型怎么变报文的路由和签名机制都不用改。下面是一份常见的申报报文骨架我按实际对接时的惯例做了简化字段名以对方提供的接口文档为准CusDeclare xmlnshttp://example.customs/declare Header MessageIdD20250101001/MessageId MessageTypeCEB/MessageType SenderCodeTS0001/SenderCode RecipientCodePLATFORM/RecipientCode SendTime2025-01-01 10:00:00/SendTime /Header Body PreEntryNoP20250101001/PreEntryNo DeclTypeEX/DeclType TradeCodeTE20250101/TradeCode GoodsList GoodsItem GName示例商品/GName GQty10/GQty GUnit个/GUnit /GoodsItem /GoodsList /Body Signature SignValuebase64字符串/SignValue /Signature /CusDeclare这段XML里MessageId是报文的唯一标识SendTime是发送时间Body里面的字段才是真正会被业务系统校验的内容。注意Signature节点不参与业务解析它存放的是对报文内容计算出的签名值。有几点容易被忽略报文根节点的命名空间不要自己改SendTime的格式必须精确到秒Body里的字段顺序一般也要固定。很多对接方在联调阶段报“报文解析失败”不是字段写错而是字段顺序和接口文档不一致。你的PHP代码应该用一个模板类或数组映射来组装报文不要手动拼字符串否则字段顺序很难控制。2.2 签名拼串先校验时间再排序最后加密海关申报接口的签名流程和常见的开放平台签名大体相似但更严格。标准流程是先把报文中约定的字段取出来按固定顺序拼成一个待签名字符串然后做摘要计算再用证书私钥对摘要做签名最后把签名值Base64编码填进Signature节点。关键点在拼串这个过程。很多人以为可以把整段XML拿去签名实际这样做很容易翻车——因为XML里任何空白字符的差异都会导致签名不一致。常见做法是单独约定一组签名要素比如“报文版本号 消息编号 发送时间 报文体内容”按文档指定的顺序拼接。// 签名要素拼接顺序严格按照接口文档定 $signString $version . $messageId . $sendTime . $bodyXml;这里有个很容易踩的细节$bodyXml必须是序列化后原样保存的那段XML文本不能是格式化之后带缩进和换行的。我一般会在组装报文时把Body里的XML单独保存一份原始字符串专门用于签名而不是从完整报文里截取。代码逻辑并不复杂核心在于顺序不能错、内容不能改。从报文体生成到签名完成中间不要做任何编码转换或格式美化操作。2.3 数据建模给回执留下“后悔药”对接海关申报不建议只把接口返回结果打印到日志就完事。申报是强流程业务从提交、接收、校验到最终放行可能要经历多轮状态变更而且每一轮回执都对应不同的处理结果。数据库里必须留一张申报记录表外加一张回执明细表这样才能在状态异常时回溯定位。我常用的表结构比较简单一张主表记录申报单本身的状态一张子表记录所有回执内容CREATE TABLE customs_declare ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, msg_id VARCHAR(64) NOT NULL COMMENT 报文消息编号, trade_no VARCHAR(64) NOT NULL COMMENT 业务单证编号, payload MEDIUMTEXT COMMENT 完整申报报文, sign_value TEXT COMMENT 请求签名值, status TINYINT DEFAULT 0 COMMENT 状态:0待提交,1已接收,2校验通过,3校验失败,9关闭, retry_count TINYINT DEFAULT 0 COMMENT 重试次数, last_error VARCHAR(255) COMMENT 最后一次错误描述, create_time DATETIME, update_time DATETIME, UNIQUE KEY uk_msg_id (msg_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE customs_receipt ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, msg_id VARCHAR(64) NOT NULL COMMENT 关联申报消息编号, receipt_type VARCHAR(32) COMMENT 回执类型, receipt_code VARCHAR(32) COMMENT 回执状态码, receipt_desc VARCHAR(255) COMMENT 回执描述, receipt_xml TEXT COMMENT 回执完整XML, create_time DATETIME, KEY idx_msg_id (msg_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这张表看似简单但解决了两个大问题一是msg_id唯一索引保证同一报文不会重复入库天然支持幂等二是payload字段存了完整报文后续排查“报文到底发了什么”时不用翻日志。回执表保留原始XML方便在状态码不一致时对照分析。3. PHP接入落地证书加载、报文拼装与异步回执的完整闭环边界条件定清楚后代码落地的步骤就清晰了。这一章直接给出一套可运行的PHP实现思路从证书准备、时间对齐、签名提交到回执解析每一段代码后面都会说明参数含义和替换方式。3.1 前置准备扩展、证书和配置项接海关申报前要先确认两件事PHP环境的openssl扩展已开启证书文件已拿到手。证书一般是一个.pfx或.p12格式的文件里面包含商户证书和私钥。不要直接把证书文件摆到Web可访问目录下建议放到项目外的独立目录并设置权限仅允许运行用户读取。如果对接的签名算法是国密SM2PHP自带的openssl_sign并不直接支持常见做法是改用对方SDK里的签名类或者用定制扩展。我一般会把签名操作封成一个接口底层实现可以按证书类型随时切换代码里不直接写死算法。// config/customs.php return [ gateway https://customs-gateway.example.com/api/declare, cert_path /var/secure/merchant.pfx, cert_password your-password, version 1.0, sender_code TS0001, recipient_code PLATFORM, ];配置项里最重要的是gateway联调环境和生产环境的地址一定分开维护不要混在一个配置里。cert_password是证书导出时的保护密码如果证书申请时设过密码这里必须填否则openssl_pkcs12_read会直接读不出来。3.2 时间对齐与报文生成海关平台的报文解析对时间同步要求很高客户端本机时间和服务器时间差太多时要么报文被判为过期要么回执里的时间戳对不上。常见做法是在请求前先从一个标准时间接口取服务器时间算出本地偏移量然后所有报文时间都按服务端时间生成。function getServerTimeOffset(): int { $response file_get_contents(https://time.example.com/api/current); $data json_decode($response, true); return strtotime($data[time]) - time(); } // 生成报文前统一校准 $offset getServerTimeOffset(); $sendTime date(Y-m-d H:i:s, time() $offset);这里的时间偏移量只做一次就够不用每个请求都去取时间。注意如果你们公司内部有NTP服务器直接让php进程同步系统时间更省事但公网环境下还是代码里做偏移最稳妥。报文生成我用一个简单的数组到XML的转换方法避免手拼字符串function buildBodyXml(array $goodsList): string { $xml new SimpleXMLElement(Body/); $xml-addChild(PreEntryNo, $goodsList[pre_entry_no]); $xml-addChild(DeclType, $goodsList[decl_type]); $goods $xml-addChild(GoodsList); foreach ($goodsList[items] as $item) { $node $goods-addChild(GoodsItem); $node-addChild(GName, $item[name]); $node-addChild(GQty, $item[qty]); $node-addChild(GUnit, $item[unit]); } return $xml-asXML(); }PreEntryNo和DeclType这种字段在真实系统里对应预录入编号和申报类型你可以直接按文档替换成自己的业务字段。SimpleXMLElement的好处是自动处理XML转义商品名称里出现特殊字符时不会把报文结构撑坏。3.3 签名与提交接口封装报文组装好之后进入签名环节。签名函数接收原始报文体和证书路径返回签名字符串function signRequest(string $bodyXml, string $certPath, string $certPassword): string { $pkcs12 file_get_contents($certPath); openssl_pkcs12_read($pkcs12, $certs, $certPassword); $privateKey openssl_pkey_get_private($certs[pkey]); $signString 1.0 . $msgId . $sendTime . $bodyXml; openssl_sign($signString, $signature, $privateKey, OPENSSL_ALGO_SHA256); return base64_encode($signature); }这段代码的逻辑是读取证书文件用openssl_pkcs12_read解析出私钥然后拼出待签名字符串最后用SHA256算法做签名。如果你的接口文档要求SM3摘要把OPENSSL_ALGO_SHA256替换成对应的常量或底层签名类即可其余流程不变。提交部分我用cURL封装加上超时控制和错误捕获function submitDeclaration(string $xml, string $signValue): array { $config config(customs); $ch curl_init($config[gateway]); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); curl_setopt($ch, CURLOPT_HTTPHEADER, [ Content-Type: application/xml; charsetutf-8, X-Signature: . $signValue, X-Msg-Id: . $msgId, ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 30); $response curl_exec($ch); $httpCode curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return [http_code $httpCode, response $response]; }这里的X-Signature和X-Msg-Id放到HTTP头里传输具体怎么传要看平台文档有的平台要求放在XML节点的Signature里而不是HTTP头里。CURLOPT_TIMEOUT设为30秒是推荐值海关申报接口响应不算快太短会导致正常慢请求被误判为超时。3.4 异步回执的解析与落库提交接口返回200不代表申报成功很多场景下平台只返回“已接收”真正的结果通过异步回执推送过来。回执一般也是一个XML报文里面带状态码、状态描述和原始消息编号。不要试图用提交接口的同步响应判断最终结果这是接入海关申报最大的思维转换。回执解析代码示例如下function parseReceipt(string $receiptXml): array { $xml simplexml_load_string($receiptXml); return [ msg_id (string)$xml-Header-MessageId, receipt_code (string)$xml-Body-ReceiptCode, receipt_desc (string)$xml-Body-ReceiptDesc, ]; }拿到回执后更新主表状态function updateDeclareStatus(string $msgId, string $code): void { $status match ($code) { 00 2, // 校验通过 99 3, // 校验失败 default 1 }; // 更新 customs_declare 表状态 }状态码00和99只是举例不同业务场景下的状态码含义可能完全不同一定要以对方文档里的状态码表为准。回执落库时要把receipt_xml原样保存一旦后续状态对不上你还能拿原始回执重新解析。4. 避坑排查六类高失败率问题与修复现场海关申报接入的坑往往不在业务字段本身而在报文边界、时间、证书这些“看起来跟业务无关”的地方。这里是我实际接单过程中遇到最多的六类问题每条都按现象、原因、解决三个层次说明。4.1 现象报文被拒收回执提示“发送时间无效”原因服务器本地时间与平台时间差超过允许范围。很多PHP服务器跑在Docker容器或云主机上系统时间漂移并不罕见尤其在没有配置NTP同步的测试环境里。解决在代码里统一做时间偏移不要依赖系统时间直接生成SendTime。我在3.2里给过一个取平台时间的函数每次进程启动时获取一次偏移量所有报文时间都用time() $offset生成这个方案能覆盖绝大部分时间不同步的场景。4.2 现象联调环境验签总是失败打印出的签名值跟文档样例完全不同原因拼接签名字符串时用了格式化后的XML字段之间的空白字符被保留进了签名原文。XML在浏览器或IDE里看起来一模一样但字节级别可能完全不同。解决签名专用字符串一定要在报文生成时就地保存也就是“先保原始串再做签名最后才拼完整报文”。任何对XML做pretty print的操作都要放在签名完成之后不要让格式化工具碰签名原文。4.3 现象回执状态显示接收成功但业务数据一直查不到原因报文内容编码不一致。接口文档要求GBK编码但代码里用UTF-8组装XML中文和特殊字符在传输过程中被转义或替换平台解析后得到的字段值跟你提交的不一样。解决在报文生成和cURL提交时统一指定编码。如果接口要求GBK可以用mb_convert_encoding把整段XML转码后再签名注意签名必须在最终编码之后进行。这块很容易被忽略因为UTF-8报文往往也能通过格式校验只是业务字段解析错位。4.4 现象同一张单被重复提交生成两条申报记录原因提交接口超时后代码直接重试但平台实际已经接收了第一条报文。解决引入幂等机制报文头里的MessageId必须全局唯一重试时复用同一MessageId表结构里对msg_id建唯一索引。重试前先查库确认该报文是否已有回执。报文的幂等不能靠数据库事务硬撑真正有效的是业务编号本身的可重入性这一点在海关场景里也是成立的。4.5 现象证书文件在本地测试正常上线后签名一直报错原因服务器上证书文件权限过大或被其他进程改动PHP进程读取到的内容与本地不一致。还有一种是线上证书已过期本地测试用的证书还是旧版。解决上线前检查证书的起止有效期用openssl_pkcs12_read解析后打印$certs[cert]里的有效时间和当前时间做对比。证书文件权限设置为只读运行用户单独持有读写权限避免被部署脚本覆盖。4.6 现象回执到达顺序与提交顺序不一致先到的回执覆盖了新状态原因异步回执没有关联消息编号或者更新状态时没有做条件判断后到的旧回执把新状态冲掉了。解决更新状态不能简单地“查单号改状态”要用msg_id做条件而且只在回执时间晚于当前记录更新时间时才更新。我的实践是给主表加一个last_receipt_time字段每次更新前先比较时间戳再决定是否写入。5. 联调与重试策略上线前最后三件必须做的事接入海关申报代码写完只算完成一半上线前的联调和验证流程才是真正决定成败的部分。第一件事是把测试和生产环境用配置开关彻底隔离。我习惯在配置里加一个app_env参数联调环境的网关地址、证书文件、商户编码全部用独立的一套。这个开关不能只靠注释切换而要写成强制检查比如代码启动时校验APP_ENV对应的网关域名前缀是否匹配不匹配直接拒绝运行从根上避免向生产环境提交测试报文。第二件事是明确重试边界。常见的错误是只要请求失败就无脑重试结果校验收到的错误回执因为重复提交而被判为恶意报文。我的习惯是连接超时、平台返回5xx这类系统异常才允许重试校验失败、业务字段错误这类带有明确状态码的问题不重试。重试时用msg_id保持不变加上指数退避策略比如第一次间隔1分钟、第二次5分钟、第三次30分钟最多三轮。第三件事是保留完整的异常现场。每次提交前把报文原文、签名原串、请求头、响应内容全部写入本地日志回执XML原始内容无论解析成功与否都要保存。这块看起来像额外工作真正出问题时就是后悔药。一次比较典型的排查经历是平台回执一直提示字段长度超限但看业务数据长度是符合的最后翻出原始报文体才发现是商品名称里包含了不可见转义字符长度计算方式跟平台不一样。没有原始报文日志这种问题根本定位不了。从那以后我每次接海关申报类需求上线前都强制走一遍完整联调流程先用联调环境提交一笔真实业务单确认状态流转正常再把重试开关打开模拟断网场景最后确认日志目录有读写权限。整套流程走完大概多花半天时间但它能筛掉大部分线上问题。希望这篇记录能帮你少走一点弯路。本文还有配套的精品资源点击获取

相关新闻

Django+B站数据分析可视化系统:完整毕业设计实战指南

Django+B站数据分析可视化系统:完整毕业设计实战指南

Django 数据可视化 B站数据分析,这三个关键词组合在一起,基本就是近几年计算机、大数据方向毕业设计里最热门的选题组合之一。我前后带过好几个学弟学妹做这套系统,从数据采集、模型设计、接口开发到ECharts图表呈现,整条链路踩…

2026/10/14 2:10:49 阅读更多 →
C++从零手写CNN与全连接网络:MNIST实战与底层原理详解

C++从零手写CNN与全连接网络:MNIST实战与底层原理详解

简介:这份资源面向深度学习初学者与具备一定C基础的开发者,用纯C从零实现卷积神经网络与全连接神经网络,并读取MNIST手写数字数据集完成训练与精度验证,帮助读者绕开框架封装,直击底层原理。压缩包共30个文件&#xff…

2026/10/14 2:10:49 阅读更多 →
四川地图shp文件处理全攻略:从坐标系体检到Web底图发布

四川地图shp文件处理全攻略:从坐标系体检到Web底图发布

简介:四川省地理信息SHP矢量数据包,面向GIS开发、城市规划、环境分析等领域的从业者、学生及科研人员,适合需要省级基础底图的各类应用场景。压缩包共200个文件,包含49组标准的shp几何、dbf属性、shx索引和prj投影配套文件&#x…

2026/10/14 4:53:16 阅读更多 →

最新新闻

M4A转MP3批量转换工具:FFmpeg参数调优与避坑指南

M4A转MP3批量转换工具:FFmpeg参数调优与避坑指南

简介:这是一款面向音频爱好者与日常办公用户的M4A转MP3格式转换工具,主要解决M4A文件在非Apple设备或较旧播放器上兼容性不足的问题,让音乐库能在更多终端顺畅播放。压缩包共2个文件,包含1个exe可执行程序与1个htm说明文档&#x…

2026/10/14 15:11:59 阅读更多 →
gem-0.2.5-src.zip源码编译指南:从解压到构建的完整流程

gem-0.2.5-src.zip源码编译指南:从解压到构建的完整流程

简介:面向半导体设备与主机通信开发者的JYUGEM开源SEMI SECS协议库源码包,基于ACE框架实现GEM/OBEM模型,支持C和Python双语言调用,可用于SECS消息解析、设备建模与通信调试。压缩包共452个文件,约824KB,以h…

2026/10/14 15:11:59 阅读更多 →
Spring事务管理:原理、实践与优化策略

Spring事务管理:原理、实践与优化策略

1. Spring事务管理基础概念在企业级应用开发中,事务管理是确保数据一致性的核心技术。Spring框架通过声明式事务管理,将我们从复杂的事务API中解放出来。我第一次接触Spring事务是在处理电商订单系统时,当时需要确保库存扣减和订单创建这两个…

2026/10/14 15:11:59 阅读更多 →
从地图到空间智能:高德AI引擎架构与开发者实战全解

从地图到空间智能:高德AI引擎架构与开发者实战全解

几年前我盯着高德地图上的红绿灯倒计时,还以为这不过是个导航App的贴心小功能。直到我参与了一个物流项目的路线规划系统,才真正意识到:那个能推测你几点到家、能预判哪条路更堵的引擎,已经从一张“会更新的照片”变成了一套能理解…

2026/10/14 15:11:59 阅读更多 →
CEF 110 Windows 非官方编译:开启 H.264/AAC 支持本地 MP4 播放

CEF 110 Windows 非官方编译:开启 H.264/AAC 支持本地 MP4 播放

简介:CEF110.0.5481.180 Windows 非官方编译版面向需要在桌面应用中嵌入现代浏览器引擎的开发者,尤其适合构建网页浏览器、媒体中心或在线视频平台等场景。该版本基于 Chromium 110 内核,重点补齐了 MP3 音频、MP4 视频及 H.264 编码支持&…

2026/10/14 15:11:59 阅读更多 →
多模态视觉+云端真机:AI助手从聊天框到实操代理的落地实践

多模态视觉+云端真机:AI助手从聊天框到实操代理的落地实践

1. 从"聊天框套壳"说起:为什么大多数AI助手止步于对话框过去两年,我接触过不下三十个号称"AI助手"的项目,其中绝大多数打开之后就是一个输入框加一个发送按钮,背后调一个通用大模型的API,再套一层…

2026/10/14 15:10:52 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/13 22:01:27 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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/14 7:53:34 阅读更多 →