java7 api urlencoder_URLEncoder in JAVA

下面有bclozel的回答 :

Hi [@georgmittendorfer](https://github.com/georgmittendorfer) ,

I think this is the expected behavior in Spring Framework (see [SPR-16202](https://jira.spring.io/browse/SPR-16202) and [SPR-14828](https://jira.spring.io/browse/SPR-14828) for some background on this).

As a general rule, providing a URI String to RestTemplate means that this String should be expanded (using optional method parameters) and then encoded. If you want to take full control over the encoding, you should then use the method variant taking a URI as a parameter.

The Spring Framework team recently added [some more documentation on the subject of URI encoding](https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/web.html#web-uri-encoding) . Does that help?

看来Spring认为这是一个正常的行为,即传入字符串的时候我就要对你进行encode,你传URI对象的时候我不管。继续点进去看看官方文档 Web on Servlet Stack:

1.5.3 中被补上了详细的使用细节,首先它将URI的组成分为两个部分,一个叫做URI template,一个叫做URI variables。然后提供了4种encode的模式:TEMPLATE_AND_VALUES:会先对template进行encode,然后在扩展的时候再对variables进行encode。

VALUES_ONLY:不会对template进行encode,在扩展之前对variables进行encode。

URI_COMPONENTS:和第二种类似,不过是在扩展之后对values进行encode。

NONE:不做任何的encode。

再来看看我们遇到的问题,在我们的一个库中,用错误的姿势使用的URI:

return webClient

.get()

.uri("/doItemHighCommissionPromotionLinkByAll?" + Utils.pojo2UrlQuery(request))

.exchange();

直接传入了一个字符串,会发现调用的方法是:

@Override

public RequestBodySpec uri(String uriTemplate, Object... uriVariables) {

attribute(URI_TEMPLATE_ATTRIBUTE, uriTemplate);

return uri(uriBuilderFactory.expand(uriTemplate, uriVariables));

}

原来我们传入的是一个没有任何占位符的uriTemplate,而现在依赖的WebClient版本中默认的encode模式是EncodingMode.URI_COMPONENTS,也就是根本不会管template部分。所以我们发现为什么传入一个字符串的时候没有被自动encode。

那么是不是把encode模式改为EncodingMode. TEMPLATE_AND_VALUES,让它会encode template就没问题了呢?也不是,比如http://api.vephp.com/hcapi?detail=1&vekey=V00003484Y95498091&para=https://uland.taobao.com/coupon/edetail?activityId=8932eb9980234090851d448195fe363c&itemId=578614572836

这个url,para传入的又是一个url,跟了一下解析代码,会发现template在解析的时候会把query map解成:

{

"detail": 1,

"vekey": "V00003484Y95498091",

"para": "https://uland.taobao.com/coupon/edetail?activityId=8932eb9980234090851d448195fe363c",

"itemId": "578614572836"

}

因为它解析query params的正则长这样:

"([^&=]+)(=?)([^&]+)?"

所以后果是para会被encode(而且还是错误的encode,这是一个针对template的encode,不是正紧的urlEncode),但是itemId部分不会。所以最终也只是得到了一个错误的encode结果。

综上所述有三种使用方式:传入的还是一个字符串,不过在构造的时候自己去做urlEncode,然后在WebClient的设置里将encode模式设为后三种。

return WebClient

.builder()

.exchangeStrategies(strategies)

.baseUrl(endpoint)

.uriBuilderFactory(providesUriBuilderFactory(endpoint));

private static DefaultUriBuilderFactory providesUriBuilderFactory(String endpoint) {

DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(endpoint);

factory.setEncodingMode(EncodingMode.NONE);

return factory;

}传入一个URI对象,构造的时候自己去做urlEncode,不用关心WebClient里的设置。

正确的使用url template和url variables进行构造,那就不用自己去做urlEncode。

URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")

.queryParam("q", "{q}")

.build("New York", "foo+bar")

public static String encodeURIComponent(String s) {

String result;

try {

result = URLEncoder.encode(s, "UTF-8")

.replaceAll("\\+", "%20")

.replaceAll("\\%21", "!")

.replaceAll("\\%27", "'")

.replaceAll("\\%28", "(")

.replaceAll("\\%29", ")")

.replaceAll("\\%7E", "~");

} catch (UnsupportedEncodingException e) {

result = s;

}

return result;

}

(好傻啊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值