首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Java -替换url中的主机?

Java -替换url中的主机?
EN

Stack Overflow用户
提问于 2017-10-10 12:54:59
回答 6查看 18.9K关注 0票数 19

在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的默认端口,所以这也是我正在努力的目标。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2017-10-10 13:17:36

Spring提供了UriComponentsBuilder。你可以这样使用它:

代码语言:javascript
运行
复制
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

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

票数 22
EN

Stack Overflow用户

发布于 2017-10-10 14:22:59

您使用java.net.URI是正确的。主机和端口(以及用户/密码,如果它们存在的话)统称为URI的授权组件:

代码语言:javascript
运行
复制
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连接的功能。)

请注意,您的一些测试是错误的。例如:

代码语言:javascript
运行
复制
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()检查它:

代码语言:javascript
运行
复制
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();
}
票数 14
EN

Stack Overflow用户

发布于 2017-10-10 12:54:59

我很快就尝试使用java.net.URIjavax.ws.rs.core.UriBuilderorg.apache.http.client.utils.URIBuilder,它们似乎都没有一个主机头可能包括一个端口的概念,所以它们都需要一些额外的逻辑来使其正确发生,而不需要有时“加倍”,而在其他时候没有正确地替换。

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

我把这种方法组合在一起,你可以用在repl.it在线测试

代码语言:javascript
运行
复制
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);
  }
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46667342

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档