从给定的url获取域名
Posted
技术标签:
【中文标题】从给定的url获取域名【英文标题】:Get domain name from given url 【发布时间】:2012-03-25 08:38:33 【问题描述】:给定一个 URL,我想提取域名(它不应包含“www”部分)。网址可以包含 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
【问题讨论】:
试试http://74.125.226.70
告诉我结果如何:)
它只返回 IP 地址。 74.125.226.70
你如何从中获得域名?假设这就是你所追求的......
例如http://www.de/
或http://www.com/
不会给出想要的结果。
【参考方案1】:
如果要解析 URL,请使用 java.net.URI
。 java.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;
应该做你想做的。
虽然它似乎工作正常,但有没有更好的方法或者有一些边缘情况可能会失败。
您编写的代码对于有效的 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 引用的潜在五个组成部分。
下面这行是分解a的正则表达式 对其组件的格式良好的 URI 引用。
^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? 12 3 4 5 6 7 8 9
上面第二行的数字只是为了便于阅读; 它们指示每个子表达式的参考点(即,每个 双括号)。
【讨论】:
@Jitendra,我建议你不要修复它们。 Java 库人员已经为您完成了这项工作。 对于 URI netUrl = new URI("www.google.com"); netUrl.getHost() 返回 NULL。我想我仍然需要检查 http:// 或 https:// @Jitendra,www.google.com
是一个相对 URL,其路径组件为 www.google.com
。例如,如果针对http://example.com/
进行解析,您将得到http://example.com/www.google.com
。
URI 主机如果包含特殊字符,则为空,例如:“öob.se”
如果域名包含下划线 (_) 则 uri.getHost();正在返回 null。【参考方案2】:
我写了一个方法(见下文),它提取一个 url 的域名并使用简单的字符串匹配。它实际上做的是提取第一个"://"
(或索引0
,如果不包含"://"
)和第一个后续"/"
(或索引String.length()
,如果没有后续"/"
)之间的位。剩余的,前面的"www(_)*."
位被砍掉。我相信在某些情况下这还不够好,但在大多数情况下应该足够好!
Mike Samuel 上面的帖子说java.net.URI
类可以做到这一点(并且比java.net.URL
类更受欢迎)但我遇到了URI
类的问题。值得注意的是,如果 url 不包含该方案,URI.getHost()
会给出一个空值,即"http(s)"
位。
/**
* 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
可能不正确
感谢您指出李。请注意,我确实用“我相信在某些情况下这还不够好......”来限定我的答案。我的回答需要针对您的具体情况稍作修改。【参考方案3】:
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
【讨论】:
【参考方案4】: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】:如果输入 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 "";
【讨论】:
【参考方案6】:试试这个: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;
【讨论】:
【参考方案7】:有一个类似的问题Extract main domain name from a given url。如果你看看这个answer ,你会发现它很容易。您只需要使用 java.net.URL
和 String
实用程序 - Split
【讨论】:
【参考方案8】:这是在 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 在another answer on this post 中评论的那样,这个问题之前已经问过:Extract main domain name from a given url。该问题的best answer 来自Satya,他建议使用Guava 的InternetDomainName.topPrivateDomain()
公共布尔 isTopPrivateDomain()
表示这个域名是否正好由一个 子域组件后跟公共后缀。例如,返回 适用于 google.com 和 foo.co.uk,但不适用于 www.google.com 或 联合王国
警告:此方法的真实结果并不意味着 域处于可作为主机寻址的***别,与主机一样多 公共后缀也是可寻址的主机。例如,域 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);
【讨论】:
【参考方案9】: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”。或“”
第二个匹配组是top level domain
第一个匹配组是非匹配组之后的任何内容以及***域之前的任何内容
两个匹配组的串联将为我们提供域/主机名。
PS : 请注意,您可以向正则表达式添加任意数量的受支持域。
【讨论】:
【参考方案10】:在我的情况下,我只需要主域而不是子域(没有“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”的 URL。
【讨论】:
【参考方案11】:以上都不错。这对我来说似乎很简单,也很容易理解。原谅引号。我在一个名为 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'
【讨论】:
【参考方案12】:我为所有案例所做和工作的方法之一是结合使用 Guava 库和正则表达式。
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() 可以是任何带有正则表达式的常用方法。
【讨论】:
【参考方案13】:为了得到实际的域名,没有子域,我使用:
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)。
【讨论】:
【参考方案14】:val host = url.split("/")[2]
【讨论】:
【参考方案15】:// 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'
【讨论】:
以上是关于从给定的url获取域名的主要内容,如果未能解决你的问题,请参考以下文章