如何在Angular中通过HTTP请求获取可使用的Javascript类以实现EditorJS自定义工具
可行落地方案整理
方案1:隔离沙箱执行(平衡灵活性与安全性)
直接用全局eval风险极高,换成new Function()配合上下文白名单的隔离方案,严格限制动态代码可访问的对象范围,杜绝访问window、cookie、localStorage等敏感资源:
// 从接口拉取工具类的纯代码文本 const toolCode = await this.http.get('/api/custom-tools/[工具标识]', {responseType: 'text'}).toPromise(); // 构造沙箱,仅暴露允许动态工具调用的API const sandbox = { document: { createElement: (tag) => { // 额外安全校验,禁止创建script等危险标签 if (['script', 'iframe'].includes(tag.toLowerCase())) throw new Error('非法标签调用'); return document.createElement(tag); } }, EditorJS: window.EditorJS // 其他你允许开放的工具类、公共方法均可在此处添加 }; // 用Function构造器执行代码,作用域绑定到沙箱 const getTool = new Function(...Object.keys(sandbox), `return ${toolCode}`); const CustomBlockTool = getTool(...Object.values(sandbox)); // 直接将CustomBlockTool加入EditorJS的tools配置即可正常使用
此方案可支持完全自定义的工具逻辑,同时把风险控制在可接受范围。
方案2:配置化通用工具(零安全风险,优先推荐)
如果自定义区块的差异仅在HTML结构、样式、输入项、保存字段等可结构化描述的维度,完全不需要传递JS类,前端提前实现一个通用动态工具类,后端仅返回JSON格式的配置即可,零动态代码执行风险:
前端通用工具类示例:
class CommonCustomTool { constructor({config}) { // config为后端返回的区块配置 this.config = config; } render() { const wrapper = document.createElement('div'); wrapper.innerHTML = this.config.template; wrapper.style.cssText = this.config.wrapperStyle; // 按配置生成输入控件 this.config.inputs.forEach(inputCfg => { const input = document.createElement(inputCfg.type === 'longtext' ? 'textarea' : 'input'); input.name = inputCfg.field; input.placeholder = inputCfg.placeholder; wrapper.appendChild(input); }); return wrapper; } save(blockContent) { const result = {}; this.config.saveFields.forEach(field => { result[field] = blockContent.querySelector(`[name="${field}"]`).value; }); return result; } }
后端返回的配置示例:
{ "toolKey": "product_banner", "toolConfig": { "wrapperStyle": "padding: 12px; border: 1px solid #f0f0f0; border-radius: 4px;", "template": "<h4>产品广告横幅</h4>", "inputs": [ {"field": "title", "type": "text", "placeholder": "输入广告标题"}, {"field": "img_url", "type": "text", "placeholder": "输入图片地址"}, {"field": "link", "type": "text", "placeholder": "输入跳转链接"} ], "saveFields": ["title", "img_url", "link"] } }
Angular侧拉取到配置后,将CommonCustomTool绑定对应配置加入EditorJS的工具列表即可,90%以上的自定义区块场景都可以用这种方案实现,完全没有安全隐患。
方案3:UMD模块动态加载(适合复杂逻辑场景)
如果自定义工具的逻辑非常复杂,配置化无法覆盖,可将每个自定义工具提前打包成独立的UMD模块,后端返回模块的静态资源地址,Angular侧用import()动态加载模块,拿到导出的工具类直接使用。这是Angular官方支持的动态加载方案,安全可控,你可以提前对所有上传的自定义工具模块做静态安全扫描,过滤恶意代码。
注意事项
无论用哪种方案,前后端都需要对所有动态返回的内容做XSS过滤,禁止注入恶意脚本。
内容的提问来源于stack exchange,提问作者Tamás Hájor
相关产品推荐
相关产品推荐

