Node.js中如何让DOMPurify钩子的async/await操作同步生效
解决DOMPurify异步钩子执行时机问题
问题核心:DOMPurify的afterSanitizeElements钩子不支持异步操作——即便钩子函数声明为async,DOMPurify也不会等待其内部的Promise完成,导致sanitize方法返回HTML字符串时,图片的base64转换还未完成,最终输出的仍是原URL。
可行解决方案:先净化DOM,再手动异步处理图片
放弃钩子方案,改为先获取净化后的DOM对象,再遍历处理所有图片,确保所有异步操作完成后再转换为HTML字符串。
修改后的代码:
const { JSDOM } = require('jsdom'); const DOMPurify = require('dompurify')(new JSDOM().window); const axios = require('axios'); // 正则判断网络图片URL const regUrlWeb = /^https?:\/\//; const getImageBase64 = async (url) => { try { const image = await axios.get(url, { responseType: 'arraybuffer' }); // 补充data URI前缀,确保浏览器能识别base64图片 const ext = url.split('.').pop().split('?')[0]; // 处理带参数的URL return `data:image/${ext};base64,${Buffer.from(image.data).toString('base64')}`; } catch (err) { console.error(`下载图片失败:${url}`, err); // 下载失败时保留原URL,也可替换为默认图片地址 return url; } }; // 1. 执行净化,返回DOM对象而非直接转成字符串 const sanitizedDom = DOMPurify.sanitize(dirty, { RETURN_DOM: true }); // 2. 获取所有img元素,并行异步处理src const imgElements = sanitizedDom.querySelectorAll('img'); await Promise.all(Array.from(imgElements).map(async (img) => { if (img.hasAttribute('src') && regUrlWeb.test(img.src)) { const base64Src = await getImageBase64(img.src); img.setAttribute('src', base64Src); } })); // 3. 将处理后的DOM转换为HTML字符串 const clean = sanitizedDom.documentElement.innerHTML; console.log(clean);
关键说明
- 使用
{ RETURN_DOM: true }选项,让DOMPurify返回完整DOM对象,而非直接输出HTML字符串; - 用
Promise.all并行处理所有图片下载,提升整体处理效率; - 所有异步操作完成后再提取HTML内容,此时img的src已全部替换为base64格式。
内容的提问来源于stack exchange,提问作者Moisés Bites
相关产品推荐
相关产品推荐

