Java-替换url中的主机?

Java-替换url中的主机?,java,Java,在java中,我想用新的主机替换url的主机部分,其中主机和url都作为字符串提供 这应该考虑到这样一个事实,即主机中可以有一个端口,如下所示 例如,给定以下输入 网址: 主机:myserver:20000 我应该从正确执行此操作的函数中获得以下输出 有人知道有哪些库或例程可以正确地在url中进行替换吗 编辑:对于我的用例,我希望我的主机替换与Javaservlet的响应相匹配。我通过运行一个本地JavaWeb服务器来尝试这一点,然后使用curl-H'Host:superduper.c

在java中,我想用新的
主机
替换url的
主机
部分,其中主机和url都作为字符串提供

这应该考虑到这样一个事实,即主机中可以有一个端口,如下所示

例如,给定以下输入
  • 网址:
  • 主机:myserver:20000
我应该从正确执行此操作的函数中获得以下输出
有人知道有哪些库或例程可以正确地在url中进行替换吗


编辑:对于我的用例,我希望我的主机替换与Javaservlet的响应相匹配。我通过运行一个本地JavaWeb服务器来尝试这一点,然后使用
curl-H'Host:superduper.com:80'对其进行测试http://localhost:8000/testurl“
并且让该端点只需从
request.getRequestURL().toString()
返回url,其中请求是
HttpServletRequest
。它返回
http://superduper.com/testurl
,因此它删除了http的默认端口,这也是我努力的目标。

我很快尝试了使用
java.net.URI
javax.ws.rs.core.UriBuilder
org.apache.http.client.utils.UriBuilder
,他们似乎都没有想到主机头可能包括一个端口,所以他们都需要一些额外的逻辑,从我所看到的,使它发生正确的,而不是端口被“加倍”有时,而不是在其他时间被正确替换

因为
java.net.URL
不需要任何额外的lib,所以我使用了它。我确实知道,如果我在某处使用
URL.equals
,这可能是个问题,因为它可能会进行DNS查找,但我不是这样认为的,因为这涵盖了我的用例,正如伪单元测试所示

我用这种方法做的,你可以


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

在这里,您需要在单独的调用中提供主机名和端口,以获得正确的编码。

或使用一些正则表达式魔术:

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;
}
publicstaticstringreplacehostinurl(stringurl,stringnewhost){
如果(url==null | | newHost==null){
返回null;
}

字符串s=url.replaceFirst((?i)(?您使用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();
}

我意识到这是一个相当古老的问题;但发布一个更简单的解决方案,以防其他人需要它

String newUrl = new URIBuilder(URI.create(originalURL)).setHost(newHost).build().toString();

我在库中添加了一个方法来执行此操作,因此您可以简单地执行以下操作:

URI uri = RawHttp.replaceHost(oldUri, "new-host");
在此提交中添加:


欢迎反馈,很快就会发布。

答案和解决方案同时发布给我留下了深刻的印象:)@pruntlar鼓励自己创建一个问题来直接回答,因为它可以帮助其他有类似问题的人().是的,如果我搜索了一些东西,但没有找到答案,并且想在某个地方记录下来以备再次需要,我会这样做。StackOverflow直接支持这一点,以帮助分享知识和促进讨论。我这样做的原因是,可能有比我更好的答案,如果有,我会切换到使用它们,但就目前而言,这适用于我的用例。谢谢!不过我会改进这个问题,我发现它有点短,如果您没有发布答案,我会倾向于询问您尝试了什么,甚至可能会关闭它。我想到的一件事是使用正则表达式替换主机。显然有缺点/陷阱有了这个,但你可以在问题中指出这些要求。@WilliMentzel-谢谢,但我认为他们需要在那里,因为这有助于验证边缘案例,并使其他人也可以轻松地在在线java repl中测试/比较他们的解决方案。很好!这表明它与Hmmm一样有效…很有趣…我必须回顾一下这个…第anks!这里还有一个测试,测试按照您的建议进行了调整。更新了答案,代码去掉了默认端口号。谢谢……这里有一个显示,这也适用于原始测试用例!如果uri.getQuery()包含转义characters@machinarium这是真的,但对于大多数用途来说可能没问题。据我所知,它似乎只会更改不需要编码的字符。%20在往返过程中幸存下来。但%33将更改为3。当您依赖外部依赖项来执行某项操作时,最好提及哪一项。我猜您使用的是
httpcomponents:httpclient
URIBuilder
?!
URI uri = RawHttp.replaceHost(oldUri, "new-host");