35

我正在尝试使用 spring 的 UriComponentsBuilder 为 oauth 交互生成一些 url。查询参数包括回调 url 和参数值等实体,其中包含空格。

尝试使用 UriComponentBuilder(因为 UriUtils 现在已弃用)

UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromHttpUrl(oauthURL);
urlBuilder.queryParam("client_id", clientId);
urlBuilder.queryParam("redirect_uri", redirectURI);
urlBuilder.queryParam("scope", "test1 test2");

String url = urlBuilder.build(false).encode().toUriString();

不幸的是,虽然 scope 参数中的空格已成功替换为“+”,但 redirect_uri 参数根本没有进行 url 编码。

例如,

redirect_uri=https://oauth2-login-demo.appspot.com/code

应该结束了

redirect_uri=https%3A%2F%2Foauth2-login-demo.appspot.com%2Fcode

但没有受到影响。深入研究代码,特别是 org.springframework.web.util.HierarchicalUriComponents.Type.QUERY_PARAM.isAllowed(c) :

if ('=' == c || '+' == c || '&' == c) {
  return false;
}
else {
  return isPchar(c) || '/' == c || '?' == c;
}

显然允许 ':' 和 '/' 字符,而口香糖不应该。它一定是在做一些其他类型的编码,虽然对于我的生活,我无法想象是什么。我在这里吠叫错误的树吗?

谢谢

4

4 回答 4

29

UriComponentsBuilder正在根据RFC 3986对您的 URI 进行编码,其中关于 URI 的“查询”组件的第 3.4 节特别值得注意。

在 'query' 组件中,字符 '/' 和 ':' 是允许的,不需要转义。

以“/”字符为例:“查询”组件(由未转义的“?”和(可选)“#”字符明确分隔)不是分层的,“/”字符没有特殊含义。所以它不需要编码。

于 2014-01-30T15:36:01.730 回答
26

据我了解, UriComponentsBuilder 不会自动编码查询参数,只是它实例化的原始 HttpUrl 。换句话说,您仍然必须显式编码:

String redirectURI= "https://oauth2-login-demo.appspot.com/code";
urlBuilder.queryParam("redirect_uri", URLEncoder.encode(redirectURI,"UTF-8" ));
于 2014-01-21T13:13:31.190 回答
5

尝试扫描 UriComponentsBuilder 文档,有一个名为 build(boolean encoded) 的方法

示例代码1:

UriComponents uriComponents = UriComponentsBuilder.fromPath("/path1/path2").build(true);

这是我的示例代码2:

UriComponents uriComponents = UriComponentsBuilder.newInstance()
            .scheme("https")
            .host("my.host")
            .path("/path1/path2").query(parameters).build(true);

URI uri= uriComponents.toUri();

ResponseEntity<MyEntityResponse> responseEntity = restTemplate.exchange(uri,
            HttpMethod.GET, entity, typeRef);
于 2018-04-09T07:43:06.887 回答
0

我尝试了上述所有解决方案,直到我得到它的工作。

在我的示例中,我试图对 ZonedDateTime 格式进行编码2022-01-21T10:17:10.228+06:00。加号是个问题。

解决我的问题是手动编码值 + 使用 URI 而不是字符串值(两者都非常重要)。

前:

restTemplate.exchange(
  UriComponentsBuilder
    .queryParam("fromDateTime", "2022-01-21T10:17:10.228+06:00")
    .build()
    .toUriString(),
  HttpMethod.GET,
  null,
  new ParameterizedTypeReference<List<MyDto>>() {}
);

后:

restTemplate.exchange(
  UriComponentsBuilder
    .queryParam("fromDateTime", URLEncoder.encode("2022-01-21T10:17:10.228+06:00", StandardCharsets.UTF_8))
    .build(true)
    .toUri(),
  HttpMethod.GET,
  null,
  new ParameterizedTypeReference<List<MyDto>>() {}
);
于 2022-01-31T14:03:19.513 回答