Spring HATEOAS升级后链接查询参数自动编码问题求助
Spring HATEOAS 1.3.7 → 2.2.0 升级后URL查询参数自动编码的解决方案
问题背景
将Spring HATEOAS从1.3.7升级到2.2.0后,生成的HAL链接中查询参数会被自动编码(比如时间戳中的冒号:被转为%3A),而旧版本不会对这类字符编码。示例对比:
1.3.7版本生成的链接
"_links": { "before": { "href": "https://localhost:8080/api/time?before=2024-03-01T06:08:07Z&itemsPerPage=10" } }
2.2.0版本生成的链接
"_links": { "before": { "href": "http://localhost:8080/api/time?before=2024-03-01T06%3A08%3A07Z&itemsPerPage=10" } }
链接生成代码:
result .add( linkTo( methodOn(TimeController.class).before(instant, itemsPerPage) ) .withRel("before"));
这一变化源于2.x版本开始严格遵循RFC 3986规范对URL参数进行编码,编码逻辑位于org.springframework.hateoas.server.core.WebHandler的TemplateVariable.prepareAndEncode(Object value)方法中。
解决方案
1. 全局自定义编码逻辑
通过实现TemplateVariable.VariableFormatter接口,自定义参数编码规则,并注册为Spring Bean,全局覆盖默认编码行为:
自定义格式化器
import org.springframework.hateoas.server.core.TemplateVariable; import org.springframework.stereotype.Component; import org.springframework.web.util.UriUtils; import java.nio.charset.StandardCharsets; @Component public class CustomVariableFormatter implements TemplateVariable.VariableFormatter { @Override public String format(Object value) { if (value == null) { return null; } String stringValue = value.toString(); // 示例:保留冒号,仅编码RFC强制要求的特殊字符 return UriUtils.encode(stringValue, StandardCharsets.UTF_8.name()) .replace("%3A", ":") .replace("%3a", ":"); } }
注册到HATEOAS配置
import org.springframework.hateoas.config.HateoasConfiguration; import org.springframework.hateoas.server.core.TemplateVariable; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class CustomHateoasConfig extends HateoasConfiguration { @Bean public TemplateVariable.VariableFormatter customVariableFormatter() { return new CustomVariableFormatter(); } }
2. 手动构建链接绕过自动编码
如果不需要全局配置,可直接使用UriComponentsBuilder手动控制编码开关:
import org.springframework.hateoas.Link; import org.springframework.web.util.UriComponentsBuilder; // 手动构建URL,禁用自动编码 String href = UriComponentsBuilder.fromHttpUrl("https://localhost:8080/api/time") .queryParam("before", instant.toString()) .queryParam("itemsPerPage", itemsPerPage) .encode(false) // 关闭自动编码 .toUriString(); // 添加到结果中 result.add(Link.of(href).withRel("before"));
注意:encode(false)会完全禁用编码,若参数包含空格、&等必须编码的字符,需手动处理以保证URL合法性。
3. 客户端适配标准编码
从合规性角度,建议客户端适配编码后的URL。Spring HATEOAS 2.x的严格编码是符合RFC规范的正确行为,旧版本的非编码行为存在潜在风险。若客户端已自行编码,需修改逻辑避免双重编码。
内容的提问来源于stack exchange,提问作者tuda224
相关产品推荐
相关产品推荐

