在富文本编辑器中处理图文资源
1k3Frontend2025-07-132025-08-24
背景
功能是在富文本编辑器创建/编辑一些图文内容, 图文图文, “文”没什么需要操心的, 主要是“图” 。
图乍一看好像也没什么担心的, 但是用户行为大概率不会按照期望去做。, 有图片上传按钮,但是用户可能会粘贴或者拖拽,刚开始暂时都还能显示, 只是个别会因为跨域或者验证限制什么的会无法显示。但这从外部来的 src 链接不是自己服务器的, 指不定什么时候就失效了。所以理想情况还是要下载存储到服务器。
- 富文本编辑器是基于
wangeditor, 用户添加图片的行为主要是- 菜单栏上传按钮, 合法流程, 没什么操心的
- 复制粘贴图片, 截图然后粘贴, 或者从文件夹拖拽图片进编辑器, 这几个也算合法流程, 因为数据类型都包含
Files会触发editor的上传事件, 就走到了合法流程。如果用的 editor 没有触发, 也可以通过监听paste/drop事件来监听- tips
:wangeditor监听了drop事件而且大概是把事件挂在了里面的元素上, 而不是外层的 container, 而 event 默认是冒泡, 从里到外传递。而我们已知的元素是 container, 如果把drop事件挂在container上,editor会成先一步完成。所以设置drop事件的时候将模式修改为使用捕获模式, 从外到里, 才能在 container 上拦截drop事件
- tips
- 选中图文, 复制粘贴图片或者拖拽进编辑器。这个
types可能包含text/html, 也有可能包含复制的时候被设置的自定义的类型, 这里面的资源就需要自己解析处理了
图文粘贴
可能包含的图片资源
Base64 encoded images- 可以不作处理, 当做 html 的一部分保存
SVG files (potential XSS risk)- 这个在被
wangeditor转化为普通标签, 也就是会不显示 - 如果需要显示, 考虑到可能包含
xss攻击, 可以通过转image src, 再放到canvas, 最后转化成图片(可以参考这篇文章使用 canvas 绘制 dom)
- 这个在被
http开头的远程链接创建临时
div获取 img 标签遍历
img标签, 筛选校验符合要求的资源。这一步就只能做筛选图片地址, 限制图片数量1
2
3
4
5const container = document.createElement('div');
container.innerHTML = html;
const imgNodes = Array.from(container.querySelectorAll('img')).filter(i => {
/** 筛选 */
})下载 =>
response=>blob=> 上传 => 替换src- 文件类型可以从
content type获取, 图片名称也可以自己生成, 尽量不要从图片链接中提取信息。如果需要从链接获取信息, 做好字符过滤 - 在下载
body之前, 可以先校验格式和尺寸, 避免浪费时间- 在
awita fetch阶段, 浏览器只下载response headers and status``, body会在response.blob(), response.arrayBuffer(), response.text(), or response.json()调用的时候被下载1
2
3
4const response = await fetch(src);
const mimeType = response.headers.get('content-type');
const contentLength = response.headers.get('content-length');
const blob = await response.blob();
- 在
- 可能会因为对方网站有授权或者跨域保护之类的, 可能会下载失败, 或者我们自己的校验没能通过之类, 种种原因如果没能上传那就删除该图片, 或者用一个默认图片代替, 让用户知道哪个失败了
- 文件类型可以从
同样是复制一堆 html 标签, html or plain text 是怎么决定的?
- 复制的文本的类型是有内容来源应用决定的, 如果是从 vscode 复制, 那么就是由 vscode 决定文本类型
Plain Text (text/plain)纯字符串, 没有任何格式HTML (text/html), 老伙伴了,可能包含xss攻击Rich Text (text/rtf)被很多编辑器(Microsoft Word, WordPad)使用的跨平台格式, 和html相比, 不支持多媒体资源, 交互功能不强Custom Formats, 自定义的类型, 比如 vscode 就自定义了自己的类型vscode-editor-data