Spring RestTemplate如何不解析PromQL中的大括号为参数占位符?
问题描述
我有一个Spring Boot Java应用,需要发起REST GET请求调用服务获取信息,但一直遇到问题,怀疑是请求中包含的大括号({和})导致的。示例请求如下:
GET https://<URL>/api/v1/query?query=count by(__name__) ({__name__=~'.+'})
注:该query值为Prometheus查询语言(PromQL),只要经过URL编码,在Postman中可正常运行。
起初我在应用中对query参数值进行URL编码,却引发了其他奇怪错误。我们怀疑存在双重编码问题,于是取消编码直接传递,现在出现以下错误:
[ERROR] 2023-05-22 13:14:12.663 [http-nio-8080-exec-1] org.apache.juli.logging.DirectJDKLog.log(DirectJDKLog.java:175) - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: Not enough variable values available to expand '__name__=~'.+''] with root cause java.lang.IllegalArgumentException: Not enough variable values available to expand '__name__=~'.+''
我理解大括号通常表示GET请求中需传入的参数占位符,但此处大括号并非REST请求的参数占位符,而是需要原样传递给Prometheus用于处理查询。发起请求的代码并未尝试传递任何参数。
请问是否有办法让RestTemplate不将这些大括号解析为参数占位符?
解决方案
方法1:转义大括号
RestTemplate默认会把{}识别为参数占位符,你可以通过将单个大括号替换为双大括号的方式转义,这样RestTemplate最终会将其解析为原始的单个大括号。比如把你的PromQL查询修改为:
String promql = "count by(__name__) ({{__name__=~'.+'}})";
将转义后的字符串作为query参数值传递即可。
方法2:手动构建URI(推荐)
使用UriComponentsBuilder直接构建完整请求URI,绕过RestTemplate的占位符解析逻辑,同时该工具会自动完成参数的正确编码,避免双重编码问题。示例代码:
String promql = "count by(__name__) ({__name__=~'.+'})"; URI requestUri = UriComponentsBuilder.fromHttpUrl("https://<URL>/api/v1/query") .queryParam("query", promql) .build() .encode() .toUri(); RestTemplate restTemplate = new RestTemplate(); String response = restTemplate.getForObject(requestUri, String.class);
方法3:全局配置RestTemplate的URI处理器
如果应用中有大量类似请求,可以自定义UriTemplateHandler来统一处理大括号转义,无需每次手动修改查询语句:
RestTemplate restTemplate = new RestTemplate(); restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory() { @Override public UriBuilder uriString(String uriTemplate) { // 自动替换所有单大括号为转义形式 String escapedTemplate = uriTemplate.replace("{", "{{").replace("}", "}}"); return super.uriString(escapedTemplate); } });
内容的提问来源于stack exchange,提问作者Joseph Gagnon
相关产品推荐
相关产品推荐

