繁体   English   中英

从给定的 url 获取域名

[英]Get domain name from given url

给定一个 URL,我想提取域名(它不应该包括“www”部分)。 Url 可以包含 http/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

Output:谷歌.com

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

“Gosling 先生——你为什么让 url equals 很糟糕?” 解释了一个这样的问题。 只需养成使用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 - 具有以http开头的路径组件的相对 URL。
  • HTTP://example.com/协议不区分大小写。
  • //example.com/ -- 与主机的协议相对 URL
  • www/foo -- 一个以www开头的路径组件的相对 URL
  • wwwexample.com -- 不以www.开头的域名www. 但以www开头。

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

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

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

由于“first-match-wins”算法与 POSIX 正则表达式使用的“贪婪”消歧方法相同,因此使用正则表达式来解析 URI 引用的潜在五个组件是很自然和常见的。

以下行是将格式良好的 URI 引用分解为其组件的正则表达式。

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

上面第二行中的数字只是为了便于阅读; 它们表示每个子表达式的参考点(即每个成对的括号)。

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

阅读更多

这是在 Guava 中使用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在这篇文章的另一个答案中评论的那样,这个问题之前已经被问到: 从给定的 url 中提取主域名 该问题的最佳答案来自Satya ,他建议使用 Guava 的InternetDomainName.topPrivateDomain()

public boolean 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);
  }
}

我编写了一个方法(见下文),它提取 url 的域名并使用简单的字符串匹配。 它实际做的是提取第一个"://" (或索引0如果不包含"://" )和第一个后续"/" (或索引String.length()如果没有后续"/" )。 剩下的,在"www(_)*."之前"www(_)*." 位被砍掉。 我相信在某些情况下这还不够好,但在大多数情况下它应该足够好!

上面 Mike Samuel 的帖子说java.net.URI类可以做到这一点(并且比java.net.URL类更java.net.URL )但我遇到了URI类的问题。 值得注意的是,如果 url 不包含方案,即"http(s)"位, URI.getHost()将给出空值。

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

我在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;

val host = url.split("/")[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];
}

使用这种方法,网址“ https://rest.webtoapp.io/llSlider?lg=en&t=8 ”将用于域“webtoapp.io”。

试试这个: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;}

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

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:请注意,您可以向正则表达式添加任意数量的受支持域。

以上都是好的。 这对我来说似乎很简单,也很容易理解。 请原谅引号。 我在一个名为 DataCenter 的类中为 Groovy 编写了它。

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

我为所有案例所做和工作的方法之一是结合使用番石榴库和正则表达式。

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() 可以是任何带有正则表达式的常用方法。

如果输入 url 是用户输入。 这个方法给出了最合适的主机名。 如果未找到,则返回输入 url。

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

为了获得实际的域名,没有子域,我使用:

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

// 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'
const val WWW = "www."

fun URL.domain(): String {
    val domain: String = this.host
    return if (domain.startsWith(ConstUtils.WWW)) {
        domain.substring(ConstUtils.WWW.length)
    } else {
        domain
    }
}

我使用正则表达式解决方案

public static String getDomainName(String url) {
    return url.replaceAll("http(s)?://|www\\.|wap\\.|/.*", "");
}

它从“http/https/www./wap”中清除 url。 从“https://stackoverflow.com/questions”中的“/questions”之后的所有不必要的东西中,我们得到的只是“stackoverflow.com”

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM