【TraeCode 上手记】让它陪我啃了块 DNN 老系统的硬骨头,富文本被过滤的连环坑

先说下我的情况。做 .NET 开发有些年头了,手头维护着一套挺老的 DNN 站点,WebForms 那种,懂的都懂,祖传代码,注释比代码还少。前两天客户报了个问题:表单里的富文本框,用户提交完之后,后台一看,加粗没了、颜色没了、链接也没了,就剩一坨纯文本。客户原话是“富文本里的格式是必须的,不能因噎废食”。

这话没毛病,但改起来才知道水有多深。

一、我想解决什么

搞清楚用户提交的 HTML 到底在哪一环被洗掉了。这个模块链路很长——前台提交、存库、后台列表显示、邮件通知、还有 CSV/XML/Excel 导出,五六条路,每条路都可能有过滤。人工捋得捋半天,而且老代码的方法名起得都很有迷惑性,不点进去看实现根本不知道它干了什么。

二、为啥这事对我重要

平时维护多、新开发少,这种排查老系统的活最耗时间也最没成就感,但又是客户最在意的事。趁九月不太忙,想试试这类活能不能让 AI 搭把手,就挑了这块骨头。

三、怎么慢慢用顺的

一开始我犯了 个错误:直接问“富文本被过滤怎么改”。它给了我一堆常规答案,什么改 web.config、关请求验证,全都没用。后来换了问法,让它别急着给方案,先把整条链路摸清楚——把提交、显示、邮件、导出每个环节取值和输出的代码都找出来列清单。这下就对了。它翻了一堆文件之后告诉我:提交端其实早就是原样存库的(之前有人修过),真正的黑手在输出端——后台显示和邮件共用的渲染方法里,用了 DNN 自带的 HtmlUtils.Clean(value, true)。

坑就坑在这个 API 上。名字叫 Clean,代码注释里也写着“净化”,一直以为它是去脚本的。让它把 DNN 源码里这个方法的实现翻出来才发现,它干的是 StripTags——把所有 HTML 标签全删,而且那个 true 参数不是“是否去 JS”,是“是否连标点一起删”(removePunctuation)。难怪导出来连逗号引号都时有时无。

换成正确的过滤(DNN 的 InputFilter 加 NoScripting,保留常用标签只剥脚本)之后,CSV 导出又炸了——富文本里的逗号、双引号、换行没做转义,一条记录被拆成七八行,Excel 打开全是错位的。这也是让它顺着导出模块的写出代码一路查到的,最后按 RFC 4180 补了引号包裹和转义。

中间还虚惊一场:代码改完编译通过,导出来一看还是老的,我以为改错了又折腾半天。后来让它比对站点 Bin 里 DLL 的修改时间和编译产物的时间,才发现是部署环节掉了链子,新 DLL 压根没拷过去。这种先怀疑自己代码的弯路,估计不少人都走过。

四、做成了什么

全部修完实测:后台显示样式回来了,邮件正文格式正常,CSV 和 XML 导出结构完整,该拦的脚本照样拦。为了说服客户,还直接用 PowerShell 加载 DNN 的 dll 把新旧两种过滤的输出贴在一起对比,白纸黑字。整个排查比我自己闷头捋快了不少,尤其是一些“我以为是 A 其实是 B”的地方,让它翻源码比我肉眼快。

给后来的人一句建议:别让 AI 直接给答案,让它先把现场摸清楚。老系统排查这种事,方向错了越努力越偏,先列清单再动手,能省一半时间。


乱的代码

改好的

1 个赞

同样在维护祖传系统,看到 HtmlUtils.Clean(value, true) 这段直接会心一笑——最坑的从来不是难懂的代码,而是名字骗人的方法,而且参数还是个裸 true,谁也想不到它是“连标点一起删”。

我前阵子踩过同款:一张配置表的字段,文档上写取值 0/1/2,库里实际存的是 1/2/3。我照文档实现完,逻辑永远差一档,最后也是让 AI 把真实数据查出来才对上。所以你那句“先把现场摸清再动手”,我这边的版本是:配置类枚举一律查真实数据,不信文档也不信命名

额外提两个可能用得上的:

  1. 你这条链路有五六个输出口(后台显示、邮件、CSV、XML、Excel),建议顺手补一组“输出快照”回归用例:同一段带加粗/颜色/链接的 HTML 灌进去,把每个出口的输出固定下来。老系统最怕的不是这次修不好,而是下次别人再改渲染方法时又静默地洗回纯文本,且没人知道。

  2. DLL 没拷过去那个虚惊,可以在页脚或启动日志里打一个编译时间戳/版本号,改完刷一眼就知道跑的是不是新产物,能省掉“先怀疑自己代码”的那半天。我们服务端发版后也是先看这个戳,再看日志。

CSV 那块按 RFC 4180 补引号转义是对的,另外提醒一句:Excel 打开 UTF-8 CSV 要带 BOM,不然中文又是一轮乱码工单。

1 个赞