
Liquid 模板前端框架集成实战React 里安全渲染的五个要点【免费下载链接】liquidLiquid markup language. Safe, customer facing template language for flexible web apps.项目地址: https://gitcode.com/gh_mirrors/li/liquid运营想自己改首页文案直接让业务方在后台编辑前端模板。这时候第一反应就该是模板文本来自外部怎么保证它不会变成注入漏洞前端框架集成里这类不可信模板问题通常用 Liquid 模板来解决。Liquid 不执行代码只负责把文本和数据组合成结果安全边界是清晰的。场景对比让非工程师写模板两种做法差在哪把模板交给工程师之外的角色通常有两条路用通用服务端引擎模板本质上就是代码。用户改一行轻则整个请求挂掉重则在服务器上执行任意逻辑风险不可控。用 Liquid模板只是标记 变量引用 过滤器语法层面就是非 eval 的用户提交的模板不会执行代码。同时编译和渲染是分离的解析做一次之后每次请求只传数据渲染开销集中在解析这一步。第一条路的问题是安全和性能都失控第二条路把能写什么提前框死了后面的配置才有意义。装好 liquidjs 并跑通 React 里的第一个模板先装依赖一行命令npm install liquidjs。引擎实例建一个就够了放在模块顶层不要在组件里反复 new。import { Liquid } from liquidjs; const engine new Liquid(); function Banner({ template, data }) { const [html, setHtml] useState(); useEffect(() { engine.parseAndRender(template, data).then(setHtml); }, [template, data]); return div dangerouslySetInnerHTML{{ __html: html }} /; }模板和 data 变了就重新渲染结果写进 DOM。Vue 侧流程一致在 mounted 或 data 的 watch 里调 parseAndRender把结果赋给绑定 v-html 的变量即可。上线前打开三道安全网严格模式、环境隔离、资源限制严格变量和过滤器。不配的话模板里引用了数据里不存在的字段渲染出来是空字符串没人报错用户只看到内容丢了排查很费劲。打开严格模式后未定义的变量和过滤器会直接抛错问题在第一现场就暴露。const options { strict_variables: true, strict_filters: true, resource_limits: { render_score_limit: 1000, render_length_limit: 10000, }, }; const engine new Liquid(options);环境隔离。多个业务场景共用一个引擎时所有标签和过滤器是全局注册的。场景 A 注册了一个叫 price 的过滤器场景 B 的同名逻辑就被覆盖了而且这种覆盖不会有任何提示。用独立环境把每个场景的注册包起来const shopEnv Liquid.Environment.build((env) { env.registerTag(customTag, CustomTag); });资源限制。上面的 resource_limits 就是这道网。不配的话一个写坏了的深层 for 循环会把浏览器主线程占满页面卡死。render_score_limit 和 render_length_limit 给渲染过程设了上限超限直接中断而不是等用户刷新。模板变多之后缓存解析结果注册业务过滤器parse 是贵的那一步render 是便宜的那一步。模板文本没变的时候没必要每次渲染都重新解析用 Map 把编译结果存下来const cache new Map(); function renderOnce(template, data) { if (!cache.has(template)) cache.set(template, engine.parse(template)); return cache.get(template).render(data); }过滤器方面把展示逻辑从模板里拿出去。比如价格格式化注册一行engine.registerFilter(price, (v) $ v.toFixed(2))模板里就能写{{ product.price | price }}模板本身不掺任何计算逻辑。两种最典型的模板商品列表和登录态问候这么写电商商品列表循环交给模板数据传一个数组格式化交给过滤器ul idproducts {% for product in products %} li{{ product.name }}: {{ product.price | price }}/li {% endfor %} /ul登录态的动态内容判断写在模板里数据只传 user 对象{% if user.logged_in %}欢迎回来{{ user.name }}{% else %}请先登录{% endif %}。两种写法有个共同点模板只描述数据长这样时显示什么不写取数逻辑数据一律由外层传进来。发布前对照这份踩坑清单在 useEffect 里重复 parse模板没变也每次重新解析白付编译开销按上一节的缓存写法收掉。data 更新后忘记重渲染useEffect 的依赖数组漏了 data接口返回了新数据但画面不动是新手最常踩的坑。严格模式没开未定义变量静默渲染成空线上表现为内容时好时坏日志里却什么都没有。多引擎或多环境并存时某一边漏注册了过滤器渲染出来是空的报错信息又不直观排查要绕一圈。一句话收束模板是数据不是代码把边界画清楚——语法边界、数据边界、资源边界然后才谈得上让业务方动手。想继续深入仓库里的 README.md 讲了语言的设计目标lib/liquid/ 是核心源码目录解析器、上下文都在里面example/ 有一个可运行的示例服务History.md 记录了版本演进。【免费下载链接】liquidLiquid markup language. Safe, customer facing template language for flexible web apps.项目地址: https://gitcode.com/gh_mirrors/li/liquid创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考