从给定的URL获取域名

时间:2012-03-07 19:36:04

标签: java url

给定一个URL,我想提取域名(它不应该包含'www'部分)。网址可以包含h​​ttp / https。这是我写的java代码。虽然看起来工作正常,但有没有更好的方法,或者是否有一些边缘情况,可能会失败。

public static String getDomainName(String url) throws MalformedURLException{
    if(!url.startsWith("http") && !url.startsWith("https")){
         url = "http://" + url;
    }        
    URL netUrl = new URL(url);
    String host = netUrl.getHost();
    if(host.startsWith("www")){
        host = host.substring("www".length()+1);
    }
    return host;
}

输入:http://google.com/blah

输出:google.com

15 个答案:

答案 0 :(得分:250)

如果要解析网址,请使用java.net.URIjava.net.URL有一堆问题 - 它的equals方法执行DNS查找,这意味着使用它的代码在与不受信任的输入一起使用时可能容易受到拒绝服务攻击。

"Mr. Gosling -- why did you make url equals suck?"解释了一个这样的问题。只是养成使用java.net.URI的习惯。

public static String getDomainName(String url) throws URISyntaxException {
    URI uri = new URI(url);
    String domain = uri.getHost();
    return domain.startsWith("www.") ? domain.substring(4) : domain;
}

应该做你想做的事。


  

虽然看起来工作正常,有没有更好的方法,或者是否有一些边缘情况,可能会失败。

您所写的代码无法使用有效的网址:

  • httpfoo/bar - 路径组件以http开头的相对网址。
  • HTTP://example.com/ - 协议不区分大小写。
  • //example.com/ - 与主持人的协议相对网址
  • www/foo - 路径组件以www
  • 开头的相对网址
  • wwwexample.com - 域名不以www.开头,而是以www开头。

分层网址具有复杂的语法。如果你试图在没有仔细阅读RFC 3986的情况下推出自己的解析器,你可能会弄错它。只需使用内置于核心库中的那个。

如果您确实需要处理java.net.URI拒绝的混乱输入,请参阅RFC 3986附录B:

  

附录B.使用正则表达式解析URI引用

     

由于“第一场比赛胜利”算法与“贪婪”相同      POSIX正则表达式使用的消歧方法,它是      自然而普通的使用正则表达式来解析      URI引用的潜在五个组件。

     

以下行是用于分解a的正则表达式      格式良好的URI引用到其组件中。

  ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
   12            3  4          5       6  7        8 9
     

上面第二行中的数字只是为了提高可读性;      它们表示每个子表达的参考点(即每个子表达式)      配对括号)。

答案 1 :(得分:66)

import java.net.*;
import java.io.*;

public class ParseURL {
  public static void main(String[] args) throws Exception {

    URL aURL = new URL("http://example.com:80/docs/books/tutorial"
                       + "/index.html?name=networking#DOWNLOADING");

    System.out.println("protocol = " + aURL.getProtocol()); //http
    System.out.println("authority = " + aURL.getAuthority()); //example.com:80
    System.out.println("host = " + aURL.getHost()); //example.com
    System.out.println("port = " + aURL.getPort()); //80
    System.out.println("path = " + aURL.getPath()); //  /docs/books/tutorial/index.html
    System.out.println("query = " + aURL.getQuery()); //name=networking
    System.out.println("filename = " + aURL.getFile()); ///docs/books/tutorial/index.html?name=networking
    System.out.println("ref = " + aURL.getRef()); //DOWNLOADING
  }
}

Read more

答案 2 :(得分:9)

以下是使用番石榴InternetDomainName.topPrivateDomain()

中的InternetDomainName.from(new URL(url).getHost()).topPrivateDomain().toString()的简短线条

鉴于http://www.google.com/blah,这将为您提供google.com。或者,给定http://www.google.co.mx,它会为您提供google.co.mx

Sa Qada中评论another answer on this post时,此问题已在早些时候提出过:Extract main domain name from a given url。这个问题的best answer来自Satya,他建议番石榴InternetDomainName.topPrivateDomain()

  

public boolean isTopPrivateDomain()

     

指示此域名是否仅由一个域名组成   子域组件后跟公共后缀。例如,退货   适用于google.com和foo.co.uk,但不适用于www.google.com或   co.uk.

     

警告:此方法的真实结果并不意味着   域名是最高级别,可以作为主机寻址,就像许多人一样   公共后缀也是可寻址的主机。例如,域名   bar.uk.com有一个公共后缀uk.com,所以它会从中返回   这种方法。但是uk.com本身就是一个可寻址的主机。

     

此方法可用于确定域是否可能是   可以设置cookie的最高级别,尽管这取决于   在个人浏览器上#39; cookie控件的实现。参见RFC   2109了解详情。

将原始帖子已包含的URL.getHost()放在一起,可以为您提供:

import com.google.common.net.InternetDomainName;

import java.net.URL;

public class DomainNameMain {

  public static void main(final String... args) throws Exception {
    final String urlString = "http://www.google.com/blah";
    final URL url = new URL(urlString);
    final String host = url.getHost();
    final InternetDomainName name = InternetDomainName.from(host).topPrivateDomain();
    System.out.println(urlString);
    System.out.println(host);
    System.out.println(name);
  }
}

答案 3 :(得分:4)

我写了一个方法(见下文),它提取了一个url的域名,并使用简单的String匹配。它实际上做的是在第一个"://"(或索引0,如果没有包含"://")和第一个后续"/"(或索引{{1}如果没有后续String.length())。剩余的前"/"位被切断。我敢肯定会出现这种情况不够好的情况,但在大多数情况下它应该足够好了!

Mike Samuel上面的帖子说"www(_)*."类可以做到这一点(并且优先于java.net.URI类)但是我遇到了java.net.URL类的问题。值得注意的是,如果网址不包含该方案,URI会给出一个空值,即URI.getHost()位。

"http(s)"

答案 4 :(得分:2)

我在创建URI对象后进行了一些小处理

 if (url.startsWith("http:/")) {
        if (!url.contains("http://")) {
            url = url.replaceAll("http:/", "http://");
        }
    } else {
        url = "http://" + url;
    }
    URI uri = new URI(url);
    String domain = uri.getHost();
    return domain.startsWith("www.") ? domain.substring(4) : domain;

答案 5 :(得分:1)

试试这个:java.net.URL;
JOptionPane.showMessageDialog(null,getDomainName(new URL(“https://en.wikipedia.org/wiki/List_of_Internet_top-level_domains”)));

public String getDomainName(URL url){
String strDomain;
String[] strhost = url.getHost().split(Pattern.quote("."));
String[] strTLD = {"com","org","net","int","edu","gov","mil","arpa"};

if(Arrays.asList(strTLD).indexOf(strhost[strhost.length-1])>=0)
    strDomain = strhost[strhost.length-2]+"."+strhost[strhost.length-1];
else if(strhost.length>2)
    strDomain = strhost[strhost.length-3]+"."+strhost[strhost.length-2]+"."+strhost[strhost.length-1];
else
    strDomain = strhost[strhost.length-2]+"."+strhost[strhost.length-1];
return strDomain;}

答案 6 :(得分:1)

有一个类似的问题Extract main domain name from a given url。如果你看一下这个answer ,你会发现它很容易。您只需使用java.net.URLString实用程序 - Split

即可

答案 7 :(得分:1)

private static final String hostExtractorRegexString = "(?:https?://)?(?:www\\.)?(.+\\.)(com|au\\.uk|co\\.in|be|in|uk|org\\.in|org|net|edu|gov|mil)";
private static final Pattern hostExtractorRegexPattern = Pattern.compile(hostExtractorRegexString);

public static String getDomainName(String url){
    if (url == null) return null;
    url = url.trim();
    Matcher m = hostExtractorRegexPattern.matcher(url);
    if(m.find() && m.groupCount() == 2) {
        return m.group(1) + m.group(2);
    }
    else {
        return null;
    }
}

说明: 正则表达式有4组。前两个是不匹配的组,接下来的两个是匹配的组。

第一个不匹配的组是“http”或“https”或“”

第二个不匹配组是“www。”或“”

第二个匹配组是top level domain

第一个匹配组是非匹配组之后的任何内容以及顶级域之前的任何内容

两个匹配组的串联将为我们提供域/主机名。

PS:请注意,您可以向正则表达式添加任意数量的受支持域。

答案 8 :(得分:1)

在我的情况下,我只需要主域,而不需要子域(没有“ www”或任何子域):

public static String getUrlDomain(String url) throws URISyntaxException {
    URI uri = new URI(url);
    String domain = uri.getHost();
    String[] domainArray = domain.split("\\.");
    if (domainArray.length == 1) {
        return domainArray[0];
    }
    else {
        return domainArray[domainArray.length - 2] + "." + domainArray[domainArray.length - 1];
    }
}

通过这种方法,域“ webtoapp.io”的网址为“ https://rest.webtoapp.io/llSlider?lg=en&t=8”。

答案 9 :(得分:0)

如果输入的网址是用户输入。此方法提供最合适的主机名。如果没有找到则返回输入网址。

private String getHostName(String urlInput) {
        urlInput = urlInput.toLowerCase();
        String hostName=urlInput;
        if(!urlInput.equals("")){
            if(urlInput.startsWith("http") || urlInput.startsWith("https")){
                try{
                    URL netUrl = new URL(urlInput);
                    String host= netUrl.getHost();
                    if(host.startsWith("www")){
                        hostName = host.substring("www".length()+1);
                    }else{
                        hostName=host;
                    }
                }catch (MalformedURLException e){
                    hostName=urlInput;
                }
            }else if(urlInput.startsWith("www")){
                hostName=urlInput.substring("www".length()+1);
            }
            return  hostName;
        }else{
            return  "";
        }
    }

答案 10 :(得分:0)

以上所有都很好。这对我来说似乎很简单,也很容易理解。请原谅报价。我是在Groovy的DataCenter类中编写的。

static String extractDomainName(String url) {
    int start = url.indexOf('://')
    if (start < 0) {
        start = 0
    } else {
        start += 3
    }
    int end = url.indexOf('/', start)
    if (end < 0) {
        end = url.length()
    }
    String domainName = url.substring(start, end)

    int port = domainName.indexOf(':')
    if (port >= 0) {
        domainName = domainName.substring(0, port)
    }
    domainName
}

这是一些junit4测试:

@Test
void shouldFindDomainName() {
    assert DataCenter.extractDomainName('http://example.com/path/') == 'example.com'
    assert DataCenter.extractDomainName('http://subpart.example.com/path/') == 'subpart.example.com'
    assert DataCenter.extractDomainName('http://example.com') == 'example.com'
    assert DataCenter.extractDomainName('http://example.com:18445/path/') == 'example.com'
    assert DataCenter.extractDomainName('example.com/path/') == 'example.com'
    assert DataCenter.extractDomainName('example.com') == 'example.com'
}

答案 11 :(得分:0)

在所有案例中,我所做的工作之一就是结合使用Guava Library和regex。

UniqueBlip

getDomain()可以是使用regex的任何常用方法。

答案 12 :(得分:0)

要获得不带子域的实际域名,我使用:

private String getDomainName(String url) throws URISyntaxException {
    String hostName = new URI(url).getHost();
    if (!hostName.contains(".")) {
        return hostName;
    }
    String[] host = hostName.split("\\.");
    return host[host.length - 2];
}

请注意,这不适用于二级域名(例如.co.uk)。

答案 13 :(得分:0)

val host = url.split("/")[2]

答案 14 :(得分:0)

// groovy
String hostname ={url -> url[(url.indexOf('://')+ 3)..-1]​.split('/')[0]​ }

hostname('http://hello.world.com/something') // return 'hello.world.com'
hostname('docker://quay.io/skopeo/stable') // return 'quay.io'