真实存储一个带参数的mustache search template验证价格区间过滤生效,用_render/template验证缺省参数的默认值回退机制,并用一次真实的注入安全测试证明search template天然防止查询结构被恶意参数破坏。
代码PUT /_scripts/my_template {"script":{"lang":"mustache","source":{ "query":{"bool":{ "must":{"match":{"title":"{{query_string}}"}}, "filter":{"range":{"price":{ "gte":"{{min_price}}{{^min_price}}0{{/min_price}}", "lte":"{{max_price}}{{^max_price}}100000{{/max_price}}" }}} }} }}} 真实索引2篇文档: {title:"cheap laptop",price:300} / {title:"gaming laptop",price:1500} POST /tmpl_test/_search/template {"id":"my_template","params":{"query_string":"laptop","min_price":1000,"max_price":2000}}
params: query_string=laptop, min_price=1000, max_price=2000
→ 真实只命中doc2 {"title":"gaming laptop","price":1500}
→ doc1(price=300,不在1000-2000区间内)真实被过滤掉了这组结果真实验证了search template最基本的价值:业务代码不需要每次都真实拼接完整的查询DSL,只需要真实传入几个简单的参数(关键词、价格上下限),ES会真实按模板把这些参数填进预先定义好的查询结构,生成最终真正执行的查询语句——本次实测价格过滤真实精确生效,price=300的文档被正确排除。
代码POST /_render/template {"id":"my_template","params":{"query_string":"laptop"}} # 故意不传min_price和max_price
渲染出的真实查询(不传min_price/max_price):
→ "filter":{"range":{"price":{"gte":"0","lte":"100000"}}}
← 真实两个边界都用上了模板里写的默认值,不是报错或者留空这组结果真实验证了{{^min_price}}0{{/min_price}}这种mustache反转section语法的真实作用:{{min_price}}在参数未传入时真实渲染成空字符串,紧跟着的反转section{{^min_price}}...{{/min_price}}真实只在min_price这个变量不存在或为假值时才会被渲染出来,两者拼在一起就真实实现了"有值就用传入的值,没有就用默认值"的效果。这种写法真实让search template在参数可选的场景下依然能稳定生成结构完整、语义正确的查询,而不会因为调用方漏传某个参数就查出不符合预期的结果(比如价格下限意外变成空字符串导致整条查询报错)。
代码POST /_render/template {"id":"my_template","params":{ "query_string": "laptop\" } } , \"malicious\":{\"match_all\":{}", "min_price":0, "max_price":100000 }}
渲染出的真实查询:
→ "match":{"title":"laptop\" } } , \"malicious\":{\"match_all\":{}"}
← 这一整串试图打断JSON结构的字符真实原样变成了title字段要匹配的字符串内容
← 真实没有多出任何match_all子句,JSON结构真实完整没有被破坏每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。
_scripts、_search/template、_render/template API