在java中,我想用新的Host
替换url的Host
部分,其中host和url都是作为字符串提供的。
这应该考虑到主机可以有一个端口这一事实,defined in the RFC
有没有人知道在网址中Host
替换的任何库或例程?
编辑:对于我的用例,我希望我的主机替换匹配java servlet会响应的内容。我通过运行本地java Web服务器尝试了这一点,然后使用curl -H 'Host:superduper.com:80' 'http://localhost:8000/testurl'
对其进行了测试,并让该端点只返回来自request.getRequestURL().toString()
的url,其中request是HttpServletRequest
。它返回了http://superduper.com/testurl
,因此它删除了http的默认端口,这也是我所追求的目标。
答案 0 :(得分:5)
Spring Framework提供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
在这里,您需要在单独的调用中提供主机名和端口以获得正确的编码。
答案 1 :(得分:4)
我很快尝试使用java.net.URI
,javax.ws.rs.core.UriBuilder
和org.apache.http.client.utils.URIBuilder
,但他们似乎都没有想到可能包含端口的主机头,所以他们都需要一些额外的从我所能看到的逻辑来使它正确发生,没有端口被“加倍”"有时,在其他时候没有正确替换。
由于java.net.URL
不需要任何额外的库,我使用它。我知道如果我在某个地方使用URL.equals
,那可能是一个问题,因为它可能会进行DNS查找,但我并不是这样,我觉得它很好,因为这涵盖了我的用例,如伪单元测试所示。
我把这种做法放在一起,你可以test it out online here at 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);
}
}
答案 2 :(得分:3)
你使用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的方案是required to be lowercase,所以虽然上述代码可以说不能完全保留所有原始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();
}
答案 3 :(得分:1)
我意识到这是一个非常老的问题;但是发布一个更简单的解决方案,以防其他人需要它。
String newUrl = new URIBuilder(URI.create(originalURL)).setHost(newHost).build().toString();
答案 4 :(得分:1)
我在RawHTTP库中添加了一种执行此操作的方法,因此您可以轻松执行以下操作:
URI uri = RawHttp.replaceHost(oldUri, "new-host");
欢迎反馈,即将发布。
答案 5 :(得分:0)
或使用一些正则表达式魔法:
public static String replaceHostInUrl(String url, String newHost) {
if (url == null || newHost == null) {
return null;
}
String s = url.replaceFirst("(?i)(?<=(https?)://)(www.)?\\w*(.com)?(:\\d*)?", newHost);
if (s.contains("http://")) {
s = s.replaceFirst(":80(?=/)", "");
} else if (s.contains("https://")) {
s = s.replaceFirst(":443(?=/)", "");
}
Matcher m = Pattern.compile("HTTPS?").matcher(s);
if (m.find()) {
s = s.replaceFirst(m.group(), m.group().toLowerCase());
}
return s;
}