我似乎无法明确地提到这一点,但是如果你使用的是java.net.URI,似乎你不能发送一个转义加号(“%2b”)作为查询arg值。查询arg被转义。
// bad: http://example.com/foo?a=%252b
new URI("http", null, "example.com", 80, "/foo", "a=%2b", null);
尝试了一个实际的“+”字符,但是按原样发送,因此服务器会将其解释为空格。
// bad: http://example.com/foo?a=+
new URI("http", null, "example.com", 80, "/foo", "a=+", null);
所以我猜你只需要自己执行查询arg键和值的百分比编码,并使用不会转义的单参数URI构造函数?也许让URI逃避“路径”,因为规则很棘手(例如,“+”字符表示加号字符,而不是空格,当在路径中时):
// good: http://example.com/foo?a=%2b
new URI(new URI("http", null, "example.com", 80, "/foo", null, null).toASCIIString() + "?a=%2b");
此外,文档声称您可以创建这样的URI,它将与源URI相同:
URI u = ...;
URI identical = new URI(u.getScheme(),
u.getUserInfo(),
u.getPath(), u.getQuery(),
u.getFragment());
但是当它包含%2b
时却不是这样URI u = new URI("http://example.com:80/foo?a=%2b");
URI identical = ...; // not identical! http://example.com:80/foo?a=+
令人沮丧,我猜这就是为什么每个人都使用apache commons或spring classes呢?
PS:http://docs.oracle.com/javase/6/docs/api/java/net/URI.html引用“以下身份也保留”部分中不存在的URI构造函数。它需要删除“权限”参数。
答案 0 :(得分:3)
我遇到了同样的麻烦。经过一番研究,我认为如果你需要加号的%2b编码,最好不要使用URI类作为结果。我正在使用这样的代码:
URI uri = new URI(...);
String asciiUrl = uri.toASCIIString();
String plusReplaced = asciiUrl.replace("+", "%2b");
答案 1 :(得分:0)
我使用Spring 5的RestTemplate
(在下面使用apache的HttpClient
)遇到了这个问题。无论我做什么,我都无法发送%2B
,这对于Couchbase的非标准(ugh ...)REST API来说是个问题。
此API期望文档ID中的空格在URL上以+
的形式转义,而文字加号为%2B
。
不幸的是,HttpClient请求执行链上的ProtocolExec
重写了所有URI,使得无法在URI的路径上发送原义的%2B
。
+
作为+
发送。%2B
也以+
的形式发送%252B
(%2B
转义的%
)按字面意义发送为
%252B
我的解决方案不仅是黑客,而且很难避免,它是编写自定义HttpClientBuilder并为MainExec
插入装饰器,该装饰器将在ProtocolExec
之后执行重写。看起来像这样:
/*
* This is a hack to circumvent Apache's HttpClient otherwise inevitable URI rewriting. This rewriting made it
* impossible to send a literal %2B in a query path as it includes a forceful reencoding that doesn't reencode the
* '+' character. This is necessary because Couchbase decided that they were too good for following standards and
* decided to use + as meaning " " (whitespace) in URI paths instead of the typical %20.
*
* As an ugly solution we wrote an HttpClientBuilder that injects a ClientExecChain that will rewrite the full path
* turning + to spaces. Maybe future versions will make this easier to accomplish.
*/
public class CustomHttpClientBuilder extends HttpClientBuilder {
@Override
protected ClientExecChain decorateMainExec(final ClientExecChain requestExecutor) {
return (
HttpRoute route,
HttpRequestWrapper request,
HttpClientContext clientContext,
HttpExecutionAware execAware) -> {
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUri(request.getURI());
uriComponentsBuilder.replacePath(request.getURI().getRawPath().replace("+", "%2B"));
request.setURI(uriComponentsBuilder.encode().build(true).toUri());
return requestExecutor.execute(route, request, clientContext, execAware);
};
}
}
这使用了Spring的UriComponentsBuilder
,但是只要最终得到格式正确的java.net.URI
,您就可以将其替换为任何其他URI构建类。
此外,它对路径值执行此操作,但对于查询args则相同。您只需要替换那些路径即可。
我真的希望没有人再失去一个星期了。
答案 2 :(得分:-2)
我使用UriBuilder来处理需要编码的所有字符。