JianFeeeee
acaf0887c7
fix(webui): 聊天图片"加载成功却显示加载失败"——HTML 属性里的反斜杠转义
## 缺陷
生产截图:图片加载成功了(img 元素在、src 正确),界面却多显示一行
蓝字「图片加载失败"/>」。
根因是内联事件属性里用了反斜杠转义:
onerror="this.parentElement.innerHTML='<span class=\"att-err\">图片加载失败</span>'"
**HTML 属性值里没有反斜杠转义** —— 那个 \" 就是引号本身,属性在
`<span class=` 之后就闭合了。浏览器切出来的是:
onerror = "this.parentElement.innerHTML='<span class="
剩下的 `att-err">图片加载失败</span>'"/>` 变成**文本节点**直接显示。
症状极具误导性:看起来像"图片坏了",实际图片是好的;而那个 onerror
因为语法错误**永不执行** —— 真失败时反而什么都不显示。
## 修法
不用内联属性(那要求以后每次拼 HTML 都记得转义规则),改成
**捕获阶段的事件委托**:
- error 事件**不冒泡**,只能在捕获阶段拿到(注释里写明了)
- 用 createElement + textContent 构造占位,不再拼 innerHTML 字符串
- 只处理 .chat-attachment-img,不影响正文里的 markdown 图片
## 顺带:两个类没有 CSS
`chat-attachment-img` 与 `att-err` 只出现在 JS 里,CSS 里一条都没有。
图片靠内联 style 撑着还能看,失败占位则完全没有样式。已补。
## 判据(2 条,变异验证)
- `TestChatAttachmentImgHasNoBrokenInlineHandler`:不许内联 onerror、
必须用 DOM API、必须有 error 监听
- `TestDashboardNoEscapedQuoteInHTMLAttributes`:通用扫描,
任何 `name="...\"...` 形态都会红(下次别人写内联事件也拦得住)
变异:把内联 onerror 放回去 ⇒ 两条同时红。
★ 写判据时踩到的坑(都已修):判据被**自己的注释**打红(注释里必须写出
错误写法来解释),需先用已有的 stripJSComments 剥离;另外我先自己写了一个
stripJSComments,与 dashboard_js_scope_test.go 的重名 —— 应复用已有的。
## 顺带修一条脆弱判据
`TestRTChild_RapidInputCollapsesToLatest` 全量跑时偶发红
("连发 50 条却跑了 5 轮")。
探针查实:连发 50 条只花 ~80µs,而测试 provider 的 ChatStream **同步瞬间
返回**,两者同量级 ⇒ 消费方能在连发过程中抢到几次执行。探针显示
dropped=48,collapse 明明生效了。
所以 `Rounds > 3` 是在测调度抖动,不是测契约。改为断言**覆盖主导**
(dropped >= burst/2)。真实通话每轮几十毫秒,连发微秒级,生产里
"轮次≈1" 自然成立。
变异验证:让 dropped 不计数 ⇒ 判据红(dropped=0(连发 50 条))。
go build/vet/gofmt 干净;go test ./... -count=1 -race = 62 ok / 0 FAIL / 0 RACE
2026-10-31 10:03:43 +08:00
..
2026-10-29 23:53:48 +08:00
2026-10-29 23:53:48 +08:00
2026-10-29 23:53:48 +08:00
2026-10-31 07:24:03 +08:00
2026-10-29 23:53:48 +08:00
2026-10-22 20:49:44 +08:00
2026-10-29 23:53:48 +08:00
2026-10-29 23:53:48 +08:00
2026-10-21 12:17:19 +08:00
2026-10-17 19:18:24 +08:00
2026-10-21 12:17:19 +08:00
2026-10-29 23:53:48 +08:00
2026-10-21 12:17:19 +08:00
2026-10-30 17:00:47 +08:00
2026-10-27 15:53:49 +08:00
2026-10-29 23:53:48 +08:00
2026-10-29 23:53:48 +08:00
2026-10-26 20:55:25 +08:00
2026-10-26 20:55:25 +08:00
2026-10-29 23:53:48 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-26 20:55:25 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-29 23:53:48 +08:00
2026-10-29 23:53:48 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-30 17:00:47 +08:00
2026-10-29 23:53:48 +08:00
2026-10-25 13:37:29 +08:00
2026-10-25 21:39:12 +08:00
2026-10-30 17:00:47 +08:00
2026-10-25 13:48:35 +08:00
2026-10-21 12:17:19 +08:00
2026-10-29 23:53:48 +08:00
2026-10-18 13:20:54 +08:00
2026-10-25 15:55:26 +08:00
2026-10-29 23:53:48 +08:00
2026-10-25 15:55:26 +08:00
2026-10-25 15:55:26 +08:00
2026-10-29 23:53:48 +08:00
2026-10-25 15:55:26 +08:00
2026-10-29 23:53:48 +08:00
2026-10-29 23:53:48 +08:00
2026-10-21 12:17:19 +08:00
2026-10-29 23:53:48 +08:00
2026-10-29 23:53:48 +08:00
2026-10-26 20:55:25 +08:00
2026-10-27 12:16:06 +08:00
2026-10-21 12:17:19 +08:00
2026-10-27 15:40:43 +08:00
2026-10-21 12:17:19 +08:00
2026-10-25 15:55:26 +08:00
2026-10-21 12:17:19 +08:00
2026-10-25 17:03:09 +08:00
2026-10-26 20:55:25 +08:00
2026-10-25 17:03:09 +08:00
2026-10-22 22:42:02 +08:00
2026-10-29 23:53:48 +08:00
2026-10-29 23:53:48 +08:00
2026-10-29 23:53:48 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-26 20:55:25 +08:00
2026-10-21 12:17:19 +08:00
2026-09-19 16:49:16 +08:00
2026-10-29 23:53:48 +08:00
2026-10-30 17:00:47 +08:00
2026-10-21 12:17:19 +08:00
2026-10-29 23:53:48 +08:00
2026-10-29 23:53:48 +08:00
2026-10-26 20:55:25 +08:00
2026-10-29 23:53:48 +08:00
2026-10-23 15:51:02 +08:00
2026-10-27 11:49:26 +08:00
2026-10-30 17:00:47 +08:00
2026-10-23 15:51:02 +08:00
2026-10-21 12:17:19 +08:00
2026-10-06 09:22:12 +08:00
2026-10-29 23:53:48 +08:00
2026-10-29 23:53:48 +08:00
2026-10-23 15:51:02 +08:00
2026-10-30 17:00:47 +08:00
2026-10-21 12:17:19 +08:00
2026-10-22 20:49:44 +08:00
2026-10-31 06:35:32 +08:00
2026-10-31 06:35:32 +08:00
2026-10-21 12:17:19 +08:00
2026-10-30 17:00:47 +08:00
2026-10-30 17:00:47 +08:00
2026-10-30 17:00:47 +08:00
2026-10-30 17:00:47 +08:00
2026-10-30 17:00:47 +08:00
2026-10-30 17:00:47 +08:00
2026-10-30 17:00:47 +08:00
2026-10-31 10:03:43 +08:00
2026-10-30 21:54:40 +08:00
2026-10-31 06:35:32 +08:00
2026-10-31 07:14:09 +08:00
2026-10-25 18:25:37 +08:00
2026-10-29 23:53:48 +08:00
2026-10-21 12:17:19 +08:00
2026-10-23 15:51:02 +08:00
2026-09-13 08:59:15 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-26 20:55:25 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-09-13 07:00:51 +08:00
2026-10-24 14:34:24 +08:00
2026-10-21 12:17:19 +08:00
2026-10-27 15:58:55 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-31 07:14:09 +08:00
2026-10-31 07:24:03 +08:00
2026-10-29 23:53:48 +08:00
2026-10-29 23:53:48 +08:00
2026-10-29 23:53:48 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-30 17:00:47 +08:00
2026-10-26 20:55:25 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-25 15:55:26 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-29 23:53:48 +08:00
2026-10-21 12:17:19 +08:00
2026-10-25 10:10:21 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-31 07:14:09 +08:00
2026-10-27 16:24:09 +08:00
2026-10-27 15:27:35 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-18 06:38:51 +08:00
2026-10-29 23:53:48 +08:00
2026-10-21 12:17:19 +08:00
2026-10-23 15:51:02 +08:00
2026-10-29 23:53:48 +08:00
2026-10-26 20:55:25 +08:00
2026-10-29 23:53:48 +08:00
2026-10-30 17:00:47 +08:00
2026-10-31 06:35:32 +08:00
2026-10-21 12:17:19 +08:00
2026-10-29 23:53:48 +08:00
2026-10-29 23:53:48 +08:00
2026-10-23 15:51:02 +08:00
2026-10-21 12:17:19 +08:00
2026-10-05 11:25:20 +08:00
2026-10-21 12:17:19 +08:00
2026-10-25 20:16:16 +08:00
2026-10-25 20:16:16 +08:00
2026-10-26 20:55:25 +08:00
2026-10-29 23:53:48 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-21 12:17:19 +08:00
2026-10-25 18:25:37 +08:00
2026-10-21 12:17:19 +08:00