从给定的URL获取域名


130

给定一个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


3
尝试http://74.125.226.70让我知道如何解决这个问题:)
Marvin Pinto 2012年

1
它只是返回IP地址。74.125.226.70
RandomQuestion

2
以及如何从中获取域名?假设这是你后..什么
马文平托

5
例如http://www.de/http://www.com/不会给出期望的结果。
Michael Konietzka'3

Answers:


287

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

“高斯林先生-为什么要使网址等于糟透了?” 解释了一个这样的问题。只是养成使用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;
}

应该做你想做的。


尽管它似乎运行良好,但有没有更好的方法或有一些极端情况可能会失败。

您编写的代码对有效的URL无效:

  • httpfoo/bar-相对URL带有以http。开头的路径组件。
  • HTTP://example.com/ -协议不区分大小写。
  • //example.com/ -主机的协议相对URL
  • www/foo -相对URL的路径部分以 www
  • wwwexample.com-这不域名开头www.,但开始用www

分层URL具有复杂的语法。如果您尝试不仔细阅读RFC 3986而推出自己的解析器,则可能会弄错。只需使用核心库中内置的一个即可。

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

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

由于“首次匹配获胜”算法与POSIX正则表达式使用的“贪婪”消歧方法相同,因此使用正则表达式来解析URI引用的潜在五个组成部分是自然而普遍的。

下一行是用于将格式正确的URI引用分解为其组件的正则表达式。

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

上面第二行中的数字仅用于增强可读性。它们指示每个子表达式(即,每个成对的括号)的参考点。


2
@Jitendra,我建议您不要修复它们。Java库人员已经为您完成了工作。
Mike Samuel

9
也是URI netUrl =新URI(“ www.google.com”); netUrl.getHost()返回NULL。我认为我仍然需要检查http://或https://
RandomQuestion'3,2012年

2
@Jitendra www.google.com是相对URL,其路径组件为www.google.com。例如,如果解决http://example.com/,您将得到http://example.com/www.google.com
Mike Samuel

谢谢迈克。如果我理解正确的话,那么使用库,是指使用URI还是上面的正则表达式?
RandomQuestion 2012年

2
如果URI主机包含特殊字符,则它将为null,例如:“öob.se”
inc

80
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
  }
}

阅读更多


15

这是InternetDomainName.topPrivateDomain()在Guava中使用的简短的代码行: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 在此帖子的另一个答案中评论的那样,该问题已在较早前提出:从给定url中提取主要域名。对该问题的最佳答案来自Satya,后者建议使用番石榴的InternetDomainName.topPrivateDomain()

公共布尔isTopPrivateDomain()

指示此域名是否仅由一个子域组件以及紧随其后的公共后缀组成。例如,对于google.com和foo.co.uk,返回true,但对于www.google.com或co.uk,则返回true。

警告:此方法的正确结果并不意味着该域位于可以作为主机寻址的最高级别,因为许多公共后缀也是可寻址的主机。例如,域bar.uk.com具有uk.com的公共后缀,因此它将通过此​​方法返回true。但是uk.com本身是可寻址的主机。

此方法可用于确定某个域是否可能是可设置Cookie的最高级别,即使这取决于各个浏览器对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);
  }
}

6

我写了一个方法(请参阅下文),该方法提取URL的域名并使用简单的String匹配。它实际上所做的是提取第一个"://"0如果没有"://"包含,则为索引)和第一个后续"/"(或String.length()没有后继,或索引"/")之间的位。剩余的前"www(_)*."一位被切掉。我敢肯定,在某些情况下这还不够好,但是在大多数情况下应该足够好了!

迈克·塞缪尔(Mike Samuel)在上面的帖子中说,java.net.URI班级可以做到这一点(这是班级的首选java.net.URL),但是我在URI班级遇到了问题。值得注意的是,URI.getHost()如果url不包含方案("http(s)"即位),则给出null值。

/**
 * Extracts the domain name from {@code url}
 * by means of String manipulation
 * rather than using the {@link URI} or {@link URL} class.
 *
 * @param url is non-null.
 * @return the domain name within {@code url}.
 */
public String getUrlDomainName(String url) {
  String domainName = new String(url);

  int index = domainName.indexOf("://");

  if (index != -1) {
    // keep everything after the "://"
    domainName = domainName.substring(index + 3);
  }

  index = domainName.indexOf('/');

  if (index != -1) {
    // keep everything before the '/'
    domainName = domainName.substring(0, index);
  }

  // check for and remove a preceding 'www'
  // followed by any sequence of characters (non-greedy)
  // followed by a '.'
  // from the beginning of the string
  domainName = domainName.replaceFirst("^www.*?\\.", "");

  return domainName;
}

我认为这可能不正确http://bob.com:8080/service/read?name=robert
Lee Meador

感谢您指出李。请注意,我的回答确实符合“我确定在某些情况下这还不够好...”。对于您的特殊情况,我的答案需要稍作修改。
阿迪尔·侯赛因

3

创建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;

2

就我而言,我只需要主域,而不需要子域(没有“ 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];
    }
    return domainArray[domainArray.length - 2] + "." + domainArray[domainArray.length - 1];
}

通过这种方法,域“ webtoapp.io” 的URL“ https://rest.webtoapp.io/llSlider?lg=en&t=8 ”将具有。


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;}


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);
    }
    return null;
}

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

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

第二个不匹配的组是“ www”。要么 ””

第二个匹配组是顶级域

第一个匹配组是不匹配组之后的任何事物,并且是顶级域之前的任何事物

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

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


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  "";
        }
    }

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'
}

0

在所有情况下我都采用的方法之一是结合使用Guava Library和regex。

public static String getDomainNameWithGuava(String url) throws MalformedURLException, 
  URISyntaxException {
    String host =new URL(url).getHost();
    String domainName="";
    try{
        domainName = InternetDomainName.from(host).topPrivateDomain().toString();
    }catch (IllegalStateException | IllegalArgumentException e){
        domainName= getDomain(url,true);
    }
    return domainName;
}

getDomain()可以是正则表达式的任何常用方法。


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)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.