从给定的网址获取域名

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

输出: google.com

249755 次浏览

如果要解析 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——具有以 http开头的路径组件的相对 URL。
  • 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

上面第二行中的数字只是为了增强可读性; 它们指示每个子表达式的引用点(即每个 双括号)。

我编写了一个方法(见下文) ,它提取一个 url 的域名,并使用简单的字符串匹配。它实际上做的是提取第一个 "://"(如果没有包含 "://",则为索引 0)和第一个后续 "/"(如果没有后续 "/",则为索引 String.length())之间的位。其余的 "www(_)*."之前的位被截断。我肯定会有这样的情况,这将不够好,但它应该在大多数情况下足够好!

Mike Samuel 在上面的文章中说,java.net.URI类可以做到这一点(而且比 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;
}
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
}
}

继续读

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

如果输入 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  "";
}
}

试试这个: java.net.URL;
ShowMessageDialog (空,getDomainName (新的 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;}

还有一个类似的问题 从给定的 URL 中提取主域名。如果你看看这个 回答,你会发现它很简单。你只需要使用 java.net.URLString实用程序-Split

下面是在番石榴中使用 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

正如 (西班牙语)这篇文章的另一个答案中所评论的那样,这个问题在前面已经被问过了: 从给定的 URL 中提取主域名。这个问题的 最佳答案来自于 萨蒂亚,它提出了番石榴的 TopPrivateDomain ()

Public boolean 是 TopPrivateDomain ()

指示此域名是否正好由一个 子域组件后跟公共后缀 对于 google.com 和 foo.co.uk 是正确的,但对于 www.google.com 或者 Co.uk.

警告: 此方法的真实结果并不意味着 域是在最高级别,这是可寻址为主机,因为许多 公共后缀也是可寻址的主机 Bar.uk.com 有一个 uk.com 的公共后缀,所以从 但是 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);
}
}
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”或“”

第二个匹配组是 顶级域名顶级域名

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

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

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

在我的情况下,我只需要主域,而不是子域(没有“ 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”将具有。

以上都很好。这个对我来说很简单,也很容易理解。原谅我的引用。我在一个名为 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
}

这里有一些军人的测试:

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

我为所有案例所做和工作的方法之一是结合使用 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 ()可以是带正则表达式的任何常用方法。

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

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

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

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

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

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

它清除来自“ http/https/www。/wap。”从所有不必要的事情后/喜欢“/问题”在“ https://stackoverflow.com/questions"”,我们只得到“ stackoverflow.com”

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