在java中,我想将url的Host
部分替换为一个新的Host
,其中主机和url都是作为字符串提供的。
这应该考虑到主机可以在其中有一个端口,如在RFC中定义。
因此,例如,给定以下输入
我应该从正确执行此操作的函数中获得以下输出
有人知道有哪些库或例程可以正确地替换url中的Host
吗?
编辑:对于我的用例,我希望我的主机替换与java的响应相匹配。我通过运行本地java服务器来尝试这一点,然后使用curl -H 'Host:superduper.com:80' 'http://localhost:8000/testurl'
对其进行测试,让该端点直接从request.getRequestURL().toString()
返回url,其中请求是一个HttpServletRequest
。它返回了http://superduper.com/testurl
,因此它删除了http的默认端口,所以这也是我正在努力的目标。
发布于 2017-10-10 13:17:36
Spring提供了UriComponentsBuilder
。你可以这样使用它:
import org.springframework.web.util.UriComponentsBuilder;
String initialUri = "http://localhost/me/out?it=5";
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(initialUri);
String modifiedUri = builder.host("myserver").port("20000").toUriString();
System.out.println(modifiedUri);
// ==> http://myserver:20000/me/out?it=5
在这里,您需要在单独的调用中提供主机名和端口,以获得正确的编码。
发布于 2017-10-10 14:22:59
您使用java.net.URI是正确的。主机和端口(以及用户/密码,如果它们存在的话)统称为URI的授权组件:
public static String replaceHostInUrl(String originalURL,
String newAuthority)
throws URISyntaxException {
URI uri = new URI(originalURL);
uri = new URI(uri.getScheme().toLowerCase(Locale.US), newAuthority,
uri.getPath(), uri.getQuery(), uri.getFragment());
return uri.toString();
}
(URI的方案是规定为小写,所以上面的代码不能完全保留所有原始URL的非权威部分,大写格式从一开始就不合法。当然,它不会影响URL连接的功能。)
请注意,您的一些测试是错误的。例如:
assertEquals("https://super/me/out?it=5", replaceHostInUrl("https://www.test.com:4300/me/out?it=5","super:443"));
assertEquals("http://super/me/out?it=5", replaceHostInUrl("http://www.test.com:4300/me/out?it=5","super:80"));
尽管https://super/me/out?it=5
在功能上与https://super:443/me/out?it=5
相同(因为https的默认端口是443),但是如果您在URI中指定了一个显式端口,那么URI有一个在其权限中指定的端口,这就是它应该保持的方式。
更新:
如果您希望删除一个显式但不必要的端口号,可以使用URL.getDefaultPort()检查它:
public static String replaceHostInUrl(String originalURL,
String newAuthority)
throws URISyntaxException,
MalformedURLException {
URI uri = new URI(originalURL);
uri = new URI(uri.getScheme().toLowerCase(Locale.US), newAuthority,
uri.getPath(), uri.getQuery(), uri.getFragment());
int port = uri.getPort();
if (port > 0 && port == uri.toURL().getDefaultPort()) {
uri = new URI(uri.getScheme(), uri.getUserInfo(),
uri.getHost(), -1, uri.getPath(),
uri.getQuery(), uri.getFragment());
}
return uri.toString();
}
发布于 2017-10-10 12:54:59
我很快就尝试使用java.net.URI
、javax.ws.rs.core.UriBuilder
和org.apache.http.client.utils.URIBuilder
,它们似乎都没有一个主机头可能包括一个端口的概念,所以它们都需要一些额外的逻辑来使其正确发生,而不需要有时“加倍”,而在其他时候没有正确地替换。
因为java.net.URL
不需要任何额外的语言,所以我使用了它。我确实知道,如果我在某个地方使用URL.equals
,这可能是一个问题,因为它可能会执行DNS查找,但我并不认为它很好,因为它涵盖了我的用例,正如伪单元测试所显示的那样。
我把这种方法组合在一起,你可以用在repl.it在线测试!
import java.net.URL;
import java.net.MalformedURLException;
class Main
{
public static void main(String[] args)
{
testReplaceHostInUrl();
}
public static void testReplaceHostInUrl()
{
assertEquals("http://myserver:20000/me/out?it=5", replaceHostInUrl("http://localhost/me/out?it=5","myserver:20000"));
assertEquals("http://myserver:20000/me/out?it=5", replaceHostInUrl("http://localhost:19000/me/out?it=5","myserver:20000"));
assertEquals("http://super/me/out?it=5", replaceHostInUrl("http://localhost:19000/me/out?it=5","super"));
assertEquals("http://super/me/out?it=5", replaceHostInUrl("http://www.test.com/me/out?it=5","super"));
assertEquals("https://myserver:20000/me/out?it=5", replaceHostInUrl("https://localhost/me/out?it=5","myserver:20000"));
assertEquals("https://myserver:20000/me/out?it=5", replaceHostInUrl("https://localhost:19000/me/out?it=5","myserver:20000"));
assertEquals("https://super/me/out?it=5", replaceHostInUrl("https://www.test.com/me/out?it=5","super"));
assertEquals("https://super/me/out?it=5", replaceHostInUrl("https://www.test.com:4300/me/out?it=5","super"));
assertEquals("https://super/me/out?it=5", replaceHostInUrl("https://www.test.com:4300/me/out?it=5","super:443"));
assertEquals("http://super/me/out?it=5", replaceHostInUrl("http://www.test.com:4300/me/out?it=5","super:80"));
assertEquals("http://super:8080/me/out?it=5", replaceHostInUrl("http://www.test.com:80/me/out?it=5","super:8080"));
assertEquals("http://super/me/out?it=5&test=5", replaceHostInUrl("http://www.test.com:80/me/out?it=5&test=5","super:80"));
assertEquals("https://super:80/me/out?it=5&test=5", replaceHostInUrl("https://www.test.com:80/me/out?it=5&test=5","super:80"));
assertEquals("https://super/me/out?it=5&test=5", replaceHostInUrl("https://www.test.com:80/me/out?it=5&test=5","super:443"));
assertEquals("http://super:443/me/out?it=5&test=5", replaceHostInUrl("http://www.test.com:443/me/out?it=5&test=5","super:443"));
assertEquals("http://super:443/me/out?it=5&test=5", replaceHostInUrl("HTTP://www.test.com:443/me/out?it=5&test=5","super:443"));
assertEquals("http://SUPERDUPER:443/ME/OUT?IT=5&TEST=5", replaceHostInUrl("HTTP://WWW.TEST.COM:443/ME/OUT?IT=5&TEST=5","SUPERDUPER:443"));
assertEquals("https://SUPERDUPER:23/ME/OUT?IT=5&TEST=5", replaceHostInUrl("HTTPS://WWW.TEST.COM:22/ME/OUT?IT=5&TEST=5","SUPERDUPER:23"));
assertEquals(null, replaceHostInUrl(null, null));
}
public static String replaceHostInUrl(String url, String newHost)
{
if (url == null || newHost == null)
{
return url;
}
try
{
URL originalURL = new URL(url);
boolean hostHasPort = newHost.indexOf(":") != -1;
int newPort = originalURL.getPort();
if (hostHasPort)
{
URL hostURL = new URL("http://" + newHost);
newHost = hostURL.getHost();
newPort = hostURL.getPort();
}
else
{
newPort = -1;
}
// Use implicit port if it's a default port
boolean isHttps = originalURL.getProtocol().equals("https");
boolean useDefaultPort = (newPort == 443 && isHttps) || (newPort == 80 && !isHttps);
newPort = useDefaultPort ? -1 : newPort;
URL newURL = new URL(originalURL.getProtocol(), newHost, newPort, originalURL.getFile());
String result = newURL.toString();
return result;
}
catch (MalformedURLException e)
{
throw new RuntimeException("Couldnt replace host in url, originalUrl=" + url + ", newHost=" + newHost);
}
}
public static void assertEquals(String expected, String actual)
{
if (expected == null && actual == null)
{
System.out.println("TEST PASSED, expected:" + expected + ", actual:" + actual);
return;
}
if (! expected.equals(actual))
throw new RuntimeException("Not equal! expected:" + expected + ", actual:" + actual);
System.out.println("TEST PASSED, expected:" + expected + ", actual:" + actual);
}
}
https://stackoverflow.com/questions/46667342
复制相似问题