如何在 Java 中对 URL/URI 中的默认虚拟主机 %2F 进行编码,使其不会更改为斜线并无法正常工作
How, in Java, to encode default vhost %2F in URL/URI so it doesn't get changed to slash and fail to work
要使用管理员 API,默认虚拟主机“/”必须编码为 %2F,根据文档:2nd paragraph, here。
我无法获取 java.net.URI
class - 大多数 http 请求的东西(例如,org.apache.http.client.methods.HttpRequestBase
)都使用 - 发出那种形式的字符串。
也就是说,我希望 new URI("http", null, "localhost", 8080, "/api/exchanges/%2F", "", null).toASCIIString()
是 http://localhost:8080/api/exchanges/%2F?
但它不是,而是 http://localhost:8080/api/exchanges/%252F?
.
如果路径是 /api/exchanges//
(双斜杠,第二个斜杠应该是默认虚拟主机,这是错误的,但没关系)那么结果是 http://localhost:8800/api/exchanges//?
(这不适用于 RabbitMQ 管理服务,它认为它是 http://localhost:8800/api/exchanges/
(一个斜杠),然后 returns 所有虚拟主机上的所有交换。
那么,秘诀是什么?
(顺便说一句,this question 不是骗子:它是关于从 File
开始的,它确实应该对路径中的“/”有专门的了解。我在这里只是谈论纯简 URI。)
仅供参考,显示各种排列的代码墙 TestNG 测试 - 这些测试全部 通过 这表明我无法通过这种方式获得 %2F
:
package com.bakins_bits;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import org.testng.annotations.Test;
public class TestSingleSlashURIPaths
{
@Test(enabled = true)
public void does_URI_or_URL_mangle_single_slash_paths_example_1()
throws MalformedURLException, UnsupportedEncodingException, URISyntaxException {
// ARRANGE
String sut = "http://localhost:8800/api/exchanges//";
// ACT
URL url = new URL(sut);
String path = "/api/exchanges//";
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), path, "", url.getRef());
String result = uri.toURL().toString();
// ASSERT
assertThat(url.toString()).isEqualTo("http://localhost:8800/api/exchanges//");
assertThat(uri.getPath()).isEqualTo("/api/exchanges//");
assertThat(uri.toString()).isEqualTo("http://localhost:8800/api/exchanges//?");
assertThat(uri.toASCIIString()).isEqualTo("http://localhost:8800/api/exchanges//?");
assertThat(result).isEqualTo("http://localhost:8800/api/exchanges//?");
}
@Test(enabled = true)
public void does_URI_or_URL_mangle_single_slash_paths_example_2()
throws MalformedURLException, UnsupportedEncodingException, URISyntaxException {
// ARRANGE
String sut = "http://localhost:8800/api/exchanges/%2F";
// ACT
URL url = new URL(sut);
String path = "/api/exchanges/%2F";
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), path, "", url.getRef());
String result = uri.toURL().toString();
// ASSERT
assertThat(url.toString()).isEqualTo("http://localhost:8800/api/exchanges/%2F");
assertThat(uri.getPath()).isEqualTo("/api/exchanges/%2F");
assertThat(uri.toString()).isEqualTo("http://localhost:8800/api/exchanges/%252F?");
assertThat(uri.toASCIIString()).isEqualTo("http://localhost:8800/api/exchanges/%252F?");
assertThat(result).isEqualTo("http://localhost:8800/api/exchanges/%252F?");
}
@Test(enabled = true)
public void does_URI_or_URL_mangle_single_slash_paths_example_3()
throws MalformedURLException, UnsupportedEncodingException, URISyntaxException {
// ARRANGE
String sut = "http://localhost:8800/api/exchanges/%252F";
// ACT
URL url = new URL(sut);
String path = "/api/exchanges/%252F"; // try pre-encoding the '%'
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), path, "", url.getRef());
String result = uri.toURL().toString();
// ASSERT
assertThat(url.toString()).isEqualTo("http://localhost:8800/api/exchanges/%252F");
assertThat(uri.getPath()).isEqualTo("/api/exchanges/%252F");
assertThat(uri.toString()).isEqualTo("http://localhost:8800/api/exchanges/%25252F?");
assertThat(uri.toASCIIString()).isEqualTo("http://localhost:8800/api/exchanges/%25252F?");
assertThat(result).isEqualTo("http://localhost:8800/api/exchanges/%25252F?");
}
}
迷人。 @dave_thompson_085 和@Suboptimal 在上面的评论中给出了答案(不确定如何给予他们代表信用,因为这些不是答案)。 (我有点视力不好,自己没试过。)
问题显然出在构造函数 URI(String scheme, String userInfo, String host, int port, String path, String query, String fragment)
中,因为构造函数 URI(String str)
有效。
请注意,即使在那种情况下(请参阅下面的测试)URI::getPath()
也不会 return 不是您期望的 %2F
(因为那是您的输入),而是 /
.
尽管如此,我还是很高兴,因为这意味着问题可以在我正在使用的客户端库中解决(它使用的是 7 参数构造函数,而不是 1 参数构造函数)。所以我会在那里提交一个错误。 (不幸的是,该库中具有此构造函数调用的方法是 private static
在辅助程序 class 中,在另一个静态方法中调用它(并放入一个被使用的数据结构),因此没有 easy/obvious 我可以制作运行时补丁(例如,subclassing)。我 讨厌 实用程序 classes。我必须构建我的自己的这个库的副本来修复它。)
谢谢!
@Test(enabled = true)
public void does_URI_or_URL_mangle_single_slash_paths_example_4()
throws MalformedURLException, UnsupportedEncodingException, URISyntaxException {
// ARRANGE
String sut = "http://localhost:8800/api/exchanges/%2F?";
// ACT
URI uri = new URI(sut);
String result = uri.toURL().toString();
// ASSERT
assertThat(uri.getPath()).isEqualTo("/api/exchanges//"); // <== this seems wrong!
assertThat(uri.toString()).isEqualTo("http://localhost:8800/api/exchanges/%2F?");
assertThat(uri.toASCIIString()).isEqualTo("http://localhost:8800/api/exchanges/%2F?");
}
要使用管理员 API,默认虚拟主机“/”必须编码为 %2F,根据文档:2nd paragraph, here。
我无法获取 java.net.URI
class - 大多数 http 请求的东西(例如,org.apache.http.client.methods.HttpRequestBase
)都使用 - 发出那种形式的字符串。
也就是说,我希望 new URI("http", null, "localhost", 8080, "/api/exchanges/%2F", "", null).toASCIIString()
是 http://localhost:8080/api/exchanges/%2F?
但它不是,而是 http://localhost:8080/api/exchanges/%252F?
.
如果路径是 /api/exchanges//
(双斜杠,第二个斜杠应该是默认虚拟主机,这是错误的,但没关系)那么结果是 http://localhost:8800/api/exchanges//?
(这不适用于 RabbitMQ 管理服务,它认为它是 http://localhost:8800/api/exchanges/
(一个斜杠),然后 returns 所有虚拟主机上的所有交换。
那么,秘诀是什么?
(顺便说一句,this question 不是骗子:它是关于从 File
开始的,它确实应该对路径中的“/”有专门的了解。我在这里只是谈论纯简 URI。)
仅供参考,显示各种排列的代码墙 TestNG 测试 - 这些测试全部 通过 这表明我无法通过这种方式获得 %2F
:
package com.bakins_bits;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import org.testng.annotations.Test;
public class TestSingleSlashURIPaths
{
@Test(enabled = true)
public void does_URI_or_URL_mangle_single_slash_paths_example_1()
throws MalformedURLException, UnsupportedEncodingException, URISyntaxException {
// ARRANGE
String sut = "http://localhost:8800/api/exchanges//";
// ACT
URL url = new URL(sut);
String path = "/api/exchanges//";
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), path, "", url.getRef());
String result = uri.toURL().toString();
// ASSERT
assertThat(url.toString()).isEqualTo("http://localhost:8800/api/exchanges//");
assertThat(uri.getPath()).isEqualTo("/api/exchanges//");
assertThat(uri.toString()).isEqualTo("http://localhost:8800/api/exchanges//?");
assertThat(uri.toASCIIString()).isEqualTo("http://localhost:8800/api/exchanges//?");
assertThat(result).isEqualTo("http://localhost:8800/api/exchanges//?");
}
@Test(enabled = true)
public void does_URI_or_URL_mangle_single_slash_paths_example_2()
throws MalformedURLException, UnsupportedEncodingException, URISyntaxException {
// ARRANGE
String sut = "http://localhost:8800/api/exchanges/%2F";
// ACT
URL url = new URL(sut);
String path = "/api/exchanges/%2F";
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), path, "", url.getRef());
String result = uri.toURL().toString();
// ASSERT
assertThat(url.toString()).isEqualTo("http://localhost:8800/api/exchanges/%2F");
assertThat(uri.getPath()).isEqualTo("/api/exchanges/%2F");
assertThat(uri.toString()).isEqualTo("http://localhost:8800/api/exchanges/%252F?");
assertThat(uri.toASCIIString()).isEqualTo("http://localhost:8800/api/exchanges/%252F?");
assertThat(result).isEqualTo("http://localhost:8800/api/exchanges/%252F?");
}
@Test(enabled = true)
public void does_URI_or_URL_mangle_single_slash_paths_example_3()
throws MalformedURLException, UnsupportedEncodingException, URISyntaxException {
// ARRANGE
String sut = "http://localhost:8800/api/exchanges/%252F";
// ACT
URL url = new URL(sut);
String path = "/api/exchanges/%252F"; // try pre-encoding the '%'
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), path, "", url.getRef());
String result = uri.toURL().toString();
// ASSERT
assertThat(url.toString()).isEqualTo("http://localhost:8800/api/exchanges/%252F");
assertThat(uri.getPath()).isEqualTo("/api/exchanges/%252F");
assertThat(uri.toString()).isEqualTo("http://localhost:8800/api/exchanges/%25252F?");
assertThat(uri.toASCIIString()).isEqualTo("http://localhost:8800/api/exchanges/%25252F?");
assertThat(result).isEqualTo("http://localhost:8800/api/exchanges/%25252F?");
}
}
迷人。 @dave_thompson_085 和@Suboptimal 在上面的评论中给出了答案(不确定如何给予他们代表信用,因为这些不是答案)。 (我有点视力不好,自己没试过。)
问题显然出在构造函数 URI(String scheme, String userInfo, String host, int port, String path, String query, String fragment)
中,因为构造函数 URI(String str)
有效。
请注意,即使在那种情况下(请参阅下面的测试)URI::getPath()
也不会 return 不是您期望的 %2F
(因为那是您的输入),而是 /
.
尽管如此,我还是很高兴,因为这意味着问题可以在我正在使用的客户端库中解决(它使用的是 7 参数构造函数,而不是 1 参数构造函数)。所以我会在那里提交一个错误。 (不幸的是,该库中具有此构造函数调用的方法是 private static
在辅助程序 class 中,在另一个静态方法中调用它(并放入一个被使用的数据结构),因此没有 easy/obvious 我可以制作运行时补丁(例如,subclassing)。我 讨厌 实用程序 classes。我必须构建我的自己的这个库的副本来修复它。)
谢谢!
@Test(enabled = true)
public void does_URI_or_URL_mangle_single_slash_paths_example_4()
throws MalformedURLException, UnsupportedEncodingException, URISyntaxException {
// ARRANGE
String sut = "http://localhost:8800/api/exchanges/%2F?";
// ACT
URI uri = new URI(sut);
String result = uri.toURL().toString();
// ASSERT
assertThat(uri.getPath()).isEqualTo("/api/exchanges//"); // <== this seems wrong!
assertThat(uri.toString()).isEqualTo("http://localhost:8800/api/exchanges/%2F?");
assertThat(uri.toASCIIString()).isEqualTo("http://localhost:8800/api/exchanges/%2F?");
}