java7 uri_Java对URI路径中的分号进行编码

本文讨论了Java在处理URI时,对于分号(;)默认不编码导致的问题,特别是在与InfluxDB交互时。通过使用`DefaultUriBuilderFactory`并设置`EncodingMode`为`VALUES_ONLY`,可以正确处理分号,避免了因未编码分号而只获取到部分查询结果的问题。
摘要由CSDN通过智能技术生成

在URL中,由于 “;” 是保留字符,Java 默认不会对它转码,在某些情况下会出现问题。

在 influxDB 中,从多个 measurement 中查询数据的SQL使用 “;” 分隔,使用 CURL 能得到正确结果

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44curl -v -G 'http://127.0.0.1:8086/query?db=test' --data-urlencode 'q=show databases;SHOW MEASUREMENTS'

...

> GET /query?db=test&q=show%20databases%3BSHOW%20MEASUREMENTS HTTP/1.1

...

<

{

"results": [

{

"statement_id": 0,

"series": [

{

"name": "databases",

"columns": [

"name"

],

"values": [

[

"_internal"

],

[

"test"

]

]

}

]

},

{

"statement_id": 1,

"series": [

{

"name": "measurements",

"columns": [

"name"

],

"values": [

[

"proxy"

]

]

}

]

}

]

}

但是在Java中,只返回第一个SQL结果。和上面 curl 的请求对比,发现是参数 q 中的 “;” 分号没有转码成 %3B 导致的。

1

2

3

4

5

6

7

8

9

10

11

12

13public class Test {

public static void main(String[] args) {

String url = "http://127.0.0.1:8086/query?db=test&q={query}";

URI uri = new UriTemplate(url).expand("show databases;show measurements");

System.out.println(uri.toString());

RestTemplate restTemplate = new RestTemplate();

HttpEntity response = restTemplate.getForEntity(uri, String.class);

System.out.println(response.getBody());

}

}

运行结果

1

2http://127.0.0.1:8086/query?db=test&q=show%20databases;show%20measurements

{"results":[{"statement_id":0,"series":[{"name":"databases","columns":["name"],"values":[["_internal"],["test"]]}]}]}

不能直接使用 ‘uri.toString().replace(“;”, “%3B”)’ 将分号替换成 “%3B”, 因为后面还会再一次编码变为 “%253B” 而报错。

后来在 spring-web-5.0.4.RELEASE.jar 中发现了 DefaultUriBuilderFactory 类。首先看一下其源码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29public class DefaultUriBuilderFactory implements UriBuilderFactory {

private final UriComponentsBuilder baseUri;

private final Map defaultUriVariables;

private DefaultUriBuilderFactory.EncodingMode encodingMode;

private boolean parsePath;

public DefaultUriBuilderFactory() {

this(UriComponentsBuilder.newInstance());

}

public DefaultUriBuilderFactory(String baseUriTemplate) {

this(UriComponentsBuilder.fromUriString(baseUriTemplate));

}

public DefaultUriBuilderFactory(UriComponentsBuilder baseUri) {

this.defaultUriVariables = new HashMap();

this.encodingMode = DefaultUriBuilderFactory.EncodingMode.URI_COMPONENT;

this.parsePath = true;

Assert.notNull(baseUri, "'baseUri' is required");

this.baseUri = baseUri;

}

public void setEncodingMode(DefaultUriBuilderFactory.EncodingMode encodingMode) {

this.encodingMode = encodingMode;

}

......

}

DefaultUriBuilderFactory 中有一个变量 encodingMode,可以通过它设置编码模式。EncodingMode 是 DefaultUriBuilderFactory 的内部类,里面定义了3中编码模式,代码如下:

1

2

3

4

5

6

7

8

9

10

11

12public class DefaultUriBuilderFactory implements UriBuilderFactory {

......

public static enum EncodingMode {

URI_COMPONENT,

VALUES_ONLY,

NONE;

private EncodingMode() {

}

}

}

使用 DefaultUriBuilderFactory 来改写上面有问题的代码后,可以正确获取结果了

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16public class Test {

public static void main(String[] args) {

String url = "http://127.0.0.1:8086/query?db=test&q={query}";

RestTemplate restTemplate = new RestTemplate();

DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory();

factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY);

URI uri = factory.expand(url,"show databases;show measurements");

System.out.println(uri.toString());

HttpEntity response = restTemplate.getForEntity(uri, String.class);

System.out.println(response.getBody());

}

}

运行结果

1

2

3http://127.0.0.1:8086/query?db=test&q=show%20databases%3Bshow%20measurements

{"results":[{"statement_id":0,"series":[{"name":"databases","columns":["name"],"values":[["_internal"],["test"]]}]},

{"statement_id":1,"series":[{"name":"measurements","columns":["name"],"values":[["proxy"]]}]}]}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值