HTML字符转义与XSS攻击防御:规则、场景与最佳实践
1. 先说清楚字符转义到底在防什么先在开篇把话说透HTML字符转义的核心使命就是防止浏览器把用户输入的内容当成可执行的代码。如果你在某个文本框里输入了scriptalert(1)/script服务端原样输出到页面上浏览器就会把它解析成一个标签然后执行里面的脚本。这就是XSS攻击跨站脚本攻击的第一性原理——你以为用户在填数据实际上他在往你的页面里塞代码。从事Web开发这么多年我见过太多被XSS打得措手不及的项目。有的团队觉得“反正我们就是个小后台没人会来打”结果某天用户反馈“登录后弹出的广告怎么回事”一查才知道是评论区被植入了恶意脚本。还有的团队以为“用了框架就万事大吉”结果在动态拼接HTML的地方栽了跟头。说到底XSS大概率不是被“攻破”的而是开发者在输出用户数据时脑子里少了一根“必须先转义”的弦。这篇内容解决什么问题一句话让你彻底搞清楚HTML转义的规则、场景、工具和踩坑点在每一个可能出问题的输出位置都能给出正确的处理方式。适合谁看前端工程师、后端工程师、全栈开发者以及所有需要跟用户输入打交道、把数据渲染到页面上的从业者。这篇内容我会从攻击原理讲到实际编码再讲完整防御链路最后是我的排查经验你可以直接照着落地。请注意一个事实转义不是“可选项”而是所有动态输出用户数据的页面必须执行的安全底线。你输出的每一段用户内容都可能是攻击者递进来的刀。2. 原理拆解XSS是怎么打进来的转义为什么能挡住2.1 浏览器解析HTML的“观察者效应”理解转义先理解浏览器。浏览器解析HTML不是一次性完成的它分阶段工作先做词法分析识别出标签、属性、文本节点碰到script或者onclick这种可执行代码的载体再进入脚本执行阶段。这里有个关键点浏览器在解析HTML时对“文本内容”和“代码结构”是严格区分处理的。当它读到时会判断后面跟的是什么。如果后面是字母它认为这是一个新标签的开始如果是/它认为这是闭合标签如果是空格、数字或者其他字符它才觉得“这是普通文本”。攻击者利用的就是这个判断逻辑——他输入的内容里带了浏览器就误以为你在闭合一个标签或者开启一个新标签。转义做的事情就是把变成lt;。浏览器在文本节点里看到lt;会先把它解码成显示出来但它不会再触发“新标签开始”的判断。这就是字符转义能防XSS的根本原因它改变了字符在HTML解析器眼中的身份让“代码性格”变成“文本性格”。2.2 三类XSS攻击场景来源各不相同存储型XSS也叫持久型恶意脚本被存到数据库里每个访问页面的用户都会中招。经典的注入点就是评论、昵称、站内信、个人简介。攻击者提交的 payload 被永久保存之后不管谁打开页面脚本都会加载执行。这类攻击危害最大因为受害者完全不需要做任何额外操作。反射型XSS非持久型恶意脚本通过URL参数传到服务端服务端没做过滤就直接拼进了响应页面。比如某搜索功能的URL长这样/search?keywordscriptalert(1)/script服务端把这个 keyword 原样渲染到结果页用户就得手动点开这个链接才会触发。攻击者通常会把链接包装成短信、邮件里的短链诱导点击。DOM型XSS这里跟服务端没关系纯粹是前端代码的问题。浏览器端的JavaScript读取location.hash、document.referrer、window.name等数据然后直接用innerHTML或document.write拼到页面里。数据根本没出过浏览器服务端自然无从过滤只能在前端做转义或过滤。三种类型的执行效果一样但修复位置完全不同。存储型和反射型可以在服务端出口统一编码DOM型必须在前端处理。我见过太多团队只修了服务端结果拿爬虫测试DOM型漏洞时页面照样弹窗。2.3 哪些字符是“高危分子”HTML上下文里真正需要重点关注的字符并不多但每一个都不能放过字符转义实体风险说明lt;开启新标签最高危字符gt;闭合标签配合使用amp;实体引用起始符会被解析成新实体quot;双引号可逃逸属性边界#x27;单引号HTML5中属性也能用单引号包裹/#x2F;闭合标签的斜杠在某些场景需要转义还有一个容易被忽视的细节空格本身不需要转义但如果你在用onerror这一类事件属性空格可以变成换行符、Tab符来绕过基于正则的简单过滤。所以凡是进入HTML属性值的用户数据转义规则比纯文本要严苛得多。3. 核心细节一套可靠的转义方案是怎么落地的3.1 转义库选型能不用手写就别手写手写转义函数看起来简单比如str.replace(//g, lt;)但真实项目的坑在于你会遗漏场景。不同场景需要转义的字符集不一样手写的函数拿到JavaScript上下文里用会把引号漏掉拿到URL参数里用不编码空格又会出乱码。成熟的项目不要重复造轮子直接用经过安全审计的库。前端/Node环境lodash的_.escape能覆盖基本的HTML实体转义处理 几个字符he库支持完整的HTML实体编解码适合处理复杂文本。服务端Javacommons-lang3的StringEscapeUtils.escapeHtml4()老牌可靠满足绝大多数场景。服务端PHPhtmlspecialchars()配合ENT_QUOTES参数这是PHP生态里最正统的做法。Pythonhtml.escape()是标准库自带函数默认转义引号开箱即用。通用领域OWASP Java Encoder针对Java生态、Microsoft AntiXSS针对.NET它们提供的都是上下文感知编码方案。这里我强烈建议你跟团队约定一个“统一出口函数”。例如在Java项目里封装一个SafeHtmlUtil.escape(String input)内部调StringEscapeUtils然后全项目只允许用这个工具类输出用户数据。这个做法比每个开发各写各的强得多——安全基线统一review成本大幅降低。3.2 解码优先级为什么顺序错了会翻车浏览器解析HTML实体有个重要机制字符引用会在词法分析阶段就被解码。也就是说lt;scriptgt;在浏览器眼里先变成script但它已经处于文本节点内所以不会真正执行。而如果你做了“二次编码”比如把用户输入的存成%26lt%3B先URL编码又HTML编码输出的结果可能变成amp;lt;。浏览器解码一次变成lt;显示在页面上是lt;而不是。这是双重编码问题虽然不产生XSS漏洞但污染了展示效果。我踩过的坑是这样的有一次在搜索页输出高亮关键字我先用URLEncoder.encode编码了用户输入再拿去做HTML拼接结果搜索词带个就直接变成乱码。排查了半天才发现是编码顺序错了。正确做法是用户原始数据先做HTML转义不要做多余的URL编码。编码顺序虽然不影响安全但直接影响用户看到的内容是否正常。3.3 属性、脚本、URL三个上下文三套规则这是最容易出事的环节。很多人知道“要转义”但拿着同一套转义规则到处用结果要么漏防要么误伤。HTML元素内容HTML context只需转义 就够了。引号在这里是普通文本字符转义了也不会有坏影响但不转义也不存在漏洞。我习惯在文本节点里一把梭把引号也转了省得后面代码挪了位置出问题。HTML属性值Attribute context必须转义 。典型漏洞input value% userInput %用户输入 onfocusalert(1)后页面变成input value onfocusalert(1)双引号闭合了value属性onfocus事件成功注入。所以在属性上下文双引号和单引号都必须转义成quot;和#x27;。JavaScript字符串Script contextHTML实体转义在这里不够用。比如var msg % userInput %;攻击者输入/scriptscriptalert(1)/script直接闭合了外层script标签。这种场景要先做JavaScript字符串转义转义\ 换行等再把转义掉以防万一。OWASP建议的规则是先转义为JSON字符串格式再做HTML实体转义。URL属性href/src context不仅要转义还要做协议限制。攻击者可能传javascript:alert(1)。防御套路是两层先校验协议只允许http/https/mailto等白名单再做URL编码。只做实体转义是不够的javascript:里没有HTML特殊字符实体转义完全拦不住。来看一个综合示例a href% safeUrl(userInput) %点击链接/a a title% escapeHtmlAttr(userInput) %悬停信息/a scriptvar msg % escapeJsStr(userInput) %;/script div% escapeHtml(userInput) %/div四个输出位置四套不同的处理函数。记不住规则的时候直接按OWASP的XSS Prevention Cheat Sheet来做它把每个上下文的规则和示例代码都列清楚了。4. 实操过程从服务端到前端的完整演练4.1 第一步确认所有用户输入出口做安全整改别一上来就写函数先盘资产。把项目里所有“用户可控数据→页面输出”的路径列出来通常集中在这几类表单提交后回显的内容搜索词、表单校验错误信息数据库里存的用户生成内容评论、文章、昵称URL参数的直接渲染location.search拿来拼DOM服务端模板里的变量输出JSP的% %、Thymeleaf的th:text、Freemarker的${}前端拼接HTML字符串的innerHTML赋值我习惯用表格建一份“输出点清单”每一行记录路径URL、参数名、输出上下文HTML/属性/JS/URL、当前是否转义。这份清单就是后续代码审查的依据。4.2 第二步服务端模板的正确写法以Java的JSP为例很多人写% request.getParameter(keyword) %直接输出这是最低级的错误。正确做法% page importorg.apache.commons.lang3.StringEscapeUtils % div搜索关键词% StringEscapeUtils.escapeHtml4(request.getParameter(keyword)) %/divThymeleaf 里注意区分th:text和th:utext——前者默认转义后者不转义。我看到过有人图省事用了th:utext还把用户评论直接塞进去这等于把转义这道门拆了。th:utext只在渲染富文本且经过白名单过滤的情况下使用。Freemarker 也一样${userContent}默认不转义 HTML需要加#escape x as x?html开启全局转义或者每个变量手动?html。后端转义的黄金法则在到达页面之前数据必须是编码状态。不要在Controller里转义后存数据库那样搜索、统计、导出都会受影响。在视图层做转义数据层保持原始数据。4.3 第三步前端框架的自动转义与例外React 和 Vue 默认帮我们处理了大部分转义。JSX 里{userContent}渲染的是文本节点框架内部会做转义Vue 的插值表达式{{ userContent }}同样安全。危险的是这些“逃生舱”React 的dangerouslySetInnerHTMLVue 的v-html原生 JavaScript 的innerHTML、outerHTML、document.write一个常见的场景是渲染富文本编辑器的内容。这个场景不能做全面转义——你得允许strong、a、img这些标签存在。正确思路是白名单过滤只允许特定标签和特定属性其他的全部剔除。推荐用 DOMPurify这个库在开发者社区的口碑很好功能就是清洗HTML字符串。基本用法import DOMPurify from dompurify; const clean DOMPurify.sanitize(userRichText, { ALLOWED_TAGS: [b, strong, i, em, a, img, ul, ol, li, p, br], ALLOWED_ATTR: [href, title, src, alt, target, rel], ALLOW_DATA_ATTR: false }); element.innerHTML clean;注意几个细节href属性要加协议校验DOMPurify 默认会拦截javascript:协议但最好再写一个白名单函数兜底target属性建议强制加_blank时同时加relnoopener noreferrer防止新窗口页面通过window.opener反向操作原页面。4.4 第四步CSP 作为纵深防御转义是有可能被绕过或遗漏的所以要用不依赖于编码正确性的兜底方案。**CSP内容安全策略**就是干这个的它告诉浏览器“只允许从哪些来源加载什么类型的资源”。一个基础的CSP响应头配置Content-Security-Policy: default-src self; script-src self; object-src none; base-uri none这条策略的效果脚本只能加载同源资源禁止插件、禁止修改base标签。万一某个转义点漏了攻击者的内联脚本也执行不了。需要内联脚本怎么办用 nonce 或 hashContent-Security-Policy: script-src self nonce-随机值页面里的script nonce随机值才会被执行攻击者不知道 nonce 的值注入的脚本就成了摆设。CSP 转义的关系是“default 高墙”和“第一道门”的关系两道都做安全感才足。4.5 第五步用编码工具函数统一拦截如果项目历史包袱重改模板工程量太大我建议封装一个前端工具函数在截获用户输入的第一时间做处理function encodeHTML(str) { return String(str) .replace(//g, amp;) .replace(//g, lt;) .replace(//g, gt;) .replace(//g, quot;) .replace(//g, #x27;); }这个函数处理五类字符覆盖HTML文本和属性上下文的基本需求。不过再次强调JavaScript字符串上下文、URL上下文它是不覆盖的。如果你用它去拼JavaScript代码let username encodeHTML(userInput); eval(greet( username ));攻击者传); alert(1); (依然能闭合引号并注入代码。工具函数不能解决所有问题关键在于选对上下文规则。5. 常见的翻车现场与排查方法5.1 双重编码导致页面显示乱码症状用户输入ATT页面显示ATamp;T。原因数据进库前转了一次义输出模板又转了一次义。排查步骤看数据库存储的是原始值还是实体值。如果是实体值说明转义发生在Dao层或Service层需要把转义逻辑挪到View层。做一个简单的取值测试就能确认输入1 2 3 2 期望显示1 2 3 2 如果显示1 lt; 2 amp;amp; 3 gt; 2 那么就是双重编码5.2 属性上下文漏转义引号被植入事件我接手过一个内部系统某列表页的筛选条件是这么写的input typetext value% request.getParameter(q) %当时服务端只做了escapeHtml但它对双引号不管用的老的escapeHtml3库。攻击者构造链接/?q onmouseoveralert(document.cookie)最终渲染input typetext value onmouseoveralert(document.cookie)修法很简单升级到escapeHtml4或自定义转义函数把quot;和#x27;也处理掉。但教训是旧库的转义范围可能不完整选型时要确认它到底转哪些字符。5.3javascript:伪协议绕过有人觉得href属性只要做了HTML实体转义就安全这是误区。javascript:alert(1)里没有 这些字符实体转义完全无效。正确做法public static String safeUrl(String url) { if (url null) return ; url url.trim().toLowerCase(); if (url.startsWith(javascript:) || url.startsWith(data:) || url.startsWith(vbscript:)) { return ; } return url; }再加一层服务端校验URL的开头必须匹配http://或https://否则返回空。前端所有target_blank的链接统一加relnoopener noreferrer。5.4 富文本过滤正则被绕过有人为了方便写了这样的过滤content.replace(/script/gi, ).replace(/on\w/gi, )这能拦一些简单的攻击但绕过方式太多了大小写混合、加注释符、用#x31;实体编码、用Tab和换行拆分属性名、嵌套标签……很多年前的XSS速查表里就有几十种变体。正则过滤不可靠富文本必须用 DOMPurify 或者服务端的白名单解析器如Jsoup的clean方法。5.5 排查XSS问题时的“笨办法”如果怀疑页面某个位置有XSS我先在输入框填这串测试数据svg/onloadalert(1)然后看页面行为。如果弹窗了说明某个上下文漏了转义如果没有任何反应继续检查渲染后的HTML源码DevTools里查看元素确认特殊字符的呈现状态。这一步能快速定位是文本节点、属性节点还是脚本节点出了问题。另外可以打开浏览器的XSS Auditor现在已经废弃了新版Chrome用Trusted Types取代调试时开启严格模式有助于暴露风险操作。6. 我现在是怎么做“全面防御”的经过多次踩坑之后我把整套思路收敛成了一个固定配置分享给你参考统一转义函数所有HTML文本输出走同一个函数属性上下文用加强版JS上下文用专门的escapeJsURL上下文有safeUrl校验。模板层强制转义Thymeleaf 一律用th:text禁用th:utext除非过了白名单JSP 一律用自定义标签或工具类禁止裸% %输出。富文本只信白名单DOMPurify 白名单配置严格精确所有的href、src做协议校验。CSP兜底新项目上线前必须配置好 CSP老项目逐步收紧策略。自动化扫描在CI里接入基础扫描工具自动检查页面有没有把用户输入直接插入到危险位置配合人工代码审查双保险。这套流程落地之后我负责的项目再也没有出现过XSS漏洞。它不会花你太多时间但对页面安全的作用是决定性的。根据我个人的实操体会转义这件事看起来技术含量不高一旦理解透了你会对“数据如何在HTML里流动”有更深的认识。最后再分享一个小技巧在新功能开发时不管输入来源是否可信一律当作“不可信输入”处理——养成这个习惯你就已经比大多数开发者安全了。

相关新闻

WebGL鼠标拖拽旋转的球面映射与四元数实现

WebGL鼠标拖拽旋转的球面映射与四元数实现

1. 为什么鼠标拖拽旋转在WebGL中不是“动动手指”那么简单很多人第一次尝试用鼠标控制WebGL场景中的立方体旋转时,会下意识地想:“不就是监听mousedown→mousemove→mouseup,然后把鼠标位移量直接加到旋转角度上吗?”我当年也是这…

2026/10/17 19:02:22 阅读更多 →
微服务三件套高可用部署实战:Docker Compose搭建Nacos、Seata、Sentinel集群

微服务三件套高可用部署实战:Docker Compose搭建Nacos、Seata、Sentinel集群

讲真的,微服务架构里事务和流控这两块,最容易让团队在“测试环境一切正常、一上线就出事”的怪圈里打转。Nacos、Seata、Sentinel这套组合,基本是Java微服务生态里绕不开的三件套。但网上教程大多是单机版演示,真到要部署成高可用…

2026/10/17 19:02:22 阅读更多 →
Spring Boot实现微信小程序登录全链路实战

Spring Boot实现微信小程序登录全链路实战

1. 项目概述:为什么“Spring Boot 微信小程序登录”是当前最稳的落地组合 最近两周,我帮三个不同背景的团队搭过小程序后端登录体系——有某高校实验室做的校园服务类轻应用,有某初创公司推的本地生活预约工具,还有一个是某传统…

2026/10/17 19:02:22 阅读更多 →

最新新闻

React Native 应用迁移 OpenHarmony 实战:数学练习应用开发与调试

React Native 应用迁移 OpenHarmony 实战:数学练习应用开发与调试

这两年我一直有意把一些跨平台项目往 OpenHarmony 上搬,刚好遇到一个适合练手的场景:数学练习。大概背景是,我手上有一份用 React Native 写的口算练习 Demo,之前在 iOS 和 Android 上都跑得很顺,后来一次技术交流中看…

2026/10/17 19:45:55 阅读更多 →
srcset与sizes实战:彻底搞懂响应式图片加载优化

srcset与sizes实战:彻底搞懂响应式图片加载优化

很多做前端的同学,工作了两三年,srcset这个名字听得很熟,但真到项目里要优化图片加载时,却总是绕开它走。问起来,答案基本是“响应式图片嘛,让不同屏幕加载不同尺寸的图”,再深入一点就说不清了…

2026/10/17 19:45:55 阅读更多 →
教育Agent实践:从个性化学习路径到自动批改的全流程落地

教育Agent实践:从个性化学习路径到自动批改的全流程落地

把一个班级四十个人的错题逐题看完,再给每个人画出“下一条该做的题”,这个工作量换成任何一位老师都需要加班到深夜。我两年前开始做“教育 Agent”这个方向时,目标很直接:能不能让系统自己完成“诊断—推荐—批改—反馈”这个循…

2026/10/17 19:45:55 阅读更多 →
iOS列表视频播放全解:AVPlayer架构、自动播放与性能优化

iOS列表视频播放全解:AVPlayer架构、自动播放与性能优化

简介:面向iOS中高级开发者的列表视频播放示例工程,模仿网易视频和今日头条的浏览交互,解决滚动列表内视频预览、点击全屏播放、切换后自动暂停等常见需求。工程基于列表控件与系统视频框架,覆盖自定义视频单元格、渲染图层、单元格…

2026/10/17 19:44:54 阅读更多 →
小学生C++竞赛初赛备考全攻略:题型拆解与高频失分点避坑

小学生C++竞赛初赛备考全攻略:题型拆解与高频失分点避坑

简介:2024年第三十一届厦门市小学生计算机C语言竞赛(初赛)试题,是一份面向小学高年级信息学初学者的完整真题试卷。全卷共四大题、45小题,满分100分,限时90分钟,内容涵盖计算机基础知识、C语法、…

2026/10/17 19:44:54 阅读更多 →
2025生成式AI流量趋势:代码补全爆发与搜索替代路径

2025生成式AI流量趋势:代码补全爆发与搜索替代路径

简介:《2025年生成式AI全球行业趋势报告》是一份面向投资者、产品经理、市场研究员和AI从业者的行业数据盘点。报告基于权威投资者情报热力图,以2025年5月9日截止的数据为节点,重点分析近12周全球生成式AI各细分方向的流量同比增长情况。内容…

2026/10/17 19:44:54 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 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/16 21:54:38 阅读更多 →
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/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练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/16 14:23:36 阅读更多 →