JavaでのURLの検証


103

特定のURLを検証するためのJavaの標準APIがあるかどうかを知りたいですか?URL文字列が正しいかどうか、つまり指定されたプロトコルが有効かどうかを確認し、次に接続を確立できるかどうかを確認します。

私はHttpURLConnectionを使用して、URLを提供し、それに接続してみました。要件の最初の部分は満たされているようですが、HttpURLConnection.connect()を実行しようとすると、「java.net.ConnectException:接続が拒否されました」という例外がスローされます。

これはプロキシ設定が原因である可能性がありますか?プロキシのシステムプロパティを設定しようとしましたが、成功しませんでした。

私が間違っていることを教えてください。


2
ここには2つの質問があるようです。URL検証とConnectExceptionの原因の特定-Ben
James

これはに対する最初のgoogleヒットであるためjava url validator、確かにここに質問があります。URLを検証する方法(文字列を見ることから)と、URLが到達可能かどうかを確認する方法(たとえば、http接続を介して)です。
vikingsteve 2016

回答:


157

コミュニティーの利益のために、
url validator java」を検索すると、このスレッドがGoogleのトップにあるため


例外のキャッチはコストがかかるため、可能な場合は回避する必要があります。文字列が有効なURLであることを確認するだけの場合は、Apache Commons ValidatorプロジェクトのUrlValidatorクラスを使用できます。

例えば:

String[] schemes = {"http","https"}; // DEFAULT schemes = "http", "https", "ftp"
UrlValidator urlValidator = new UrlValidator(schemes);
if (urlValidator.isValid("ftp://foo.bar.com/")) {
   System.out.println("URL is valid");
} else {
   System.out.println("URL is invalid");
}

37
そのURLValidatorクラスは非推奨とマークされています。推奨URLValidatorは、ルーチンのパッケージである:commons.apache.org/validator/apidocs/org/apache/commons/...
SPEKTR

6
@Spektrリンクを修正しました。ありがとう。
ヨナタン

18
これが標準のAPIである
b1nary.atr0phy '27 / 07/27

2
UrlValidatorには一連の既知の問題があります。より積極的に維持されている代替ライブラリはありますか?
Alex Averbuch 2013

9
@AlexAverbuch:UrlValidatorの問題の概要を教えてください。それらが存在していると言うだけではあまり役に立ちませんが、それらが何であるかは言いません。
cdmckay

33

URLオブジェクトとオブジェクトの両方を作成する必要がありURLConnectionます。次のコードは、URLの形式と接続を確立できるかどうかの両方をテストします。

try {
    URL url = new URL("http://www.yoursite.com/");
    URLConnection conn = url.openConnection();
    conn.connect();
} catch (MalformedURLException e) {
    // the URL is not in a valid form
} catch (IOException e) {
    // the connection couldn't be established
}

不正なURL /問題をチェックする方法は複数あることに注意してください。たとえば、にURLを使用する場合、不正なURLがあればスローnew HttpGet(url)をキャッチできますIllegalArgumentException HttpGet(...)。そしてHttpResponse、データの取得に問題がある場合にも、あなたに何かを投げます。
Peter Ajtai

2
接続はホストの可用性のみを検証します。URLの有効性とは関係ありません。
Andrey Rodionov

2
MalformedURLExceptionは、有効な形式のURLをテストする安全な方法ではありません。この答えは誤解を招くものです。
マーティン

1
@マーティン:なぜそれが安全ではないの詳しく説明できますか?
Jeroen Vannevel 2014年

28
これは非常に高価です。openConnection / connectは実際にはhttpリソースへの接続を試みます。これは、URLを確認するために私が今まで見た中で最も高価な方法の1つであるに違いありません。
Glenn Bech 2014年

33

java.net.URL実際、このクラスはURLを検証するための良い方法ではありません。MalformedURLExceptionされていない建設中に、すべての不正な形式のURLで投げ。キャッチIOExceptionjava.net.URL#openConnection().connect()てもURLは検証されません。接続が確立できるかどうかを伝えるだけです。

次のコードを検討してください。

    try {
        new URL("http://.com");
        new URL("http://com.");
        new URL("http:// ");
        new URL("ftp://::::@example.com");
    } catch (MalformedURLException malformedURLException) {
        malformedURLException.printStackTrace();
    }

..これは例外をスローしません。

私は、文脈自由文法を使用して実装された検証APIを使用するか、非常に単純化された検証では正規表現を使用することをお勧めします。しかし、私はこれのために優れたまたは標準のAPIを提案する人が必要です、私は最近それを自分で検索し始めました。

URL#toURI()例外の処理と組み合わせるとjava.net. URISyntaxException、URLの検証が容易になること が示唆されています。ただし、このメソッドは、上記の非常に単純なケースの1つのみをキャッチします。

結論として、URLを検証する標準のJava URLパーサーはありません。


この問題の解決策を見つけましたか?
kidd0 14年

@ bi0s.kidd0使用できるライブラリはいくつかありますが、独自のライブラリを作成することにしました。完全ではありませんが、ドメインまたはIP(v4とv6の両方)のいずれかを含むURLを含め、関心のあるものを解析できます。github.com/jajja/arachne
マーティン

15

標準API のみを使用して、文字列をURLオブジェクトに渡し、それをオブジェクトに変換しURIます。これにより、RFC2396標準に従ってURLの有効性が正確に判断されます。

例:

public boolean isValidURL(String url) {

    try {
        new URL(url).toURI();
    } catch (MalformedURLException | URISyntaxException e) {
        return false;
    }

    return true;
}

5
このstring-> url-> uri検証スキームは、これらのテストケースが有効であると報告していることに注意してください: "http://.com" " com。" "ftp:// :::: @ example.com" "http:/test.com" "http:test.com" "http:/:"これは標準APIですが、適用される検証ルールは何を期待しています。
DaveK 2013年

10

android.webkit.URLUtilアンドロイドで使用してください:

URLUtil.isValidUrl(URL_STRING);

注:これは単にURLの初期スキームをチェックするだけであり、URL全体が有効であるということではありません。


2
もちろん、androidアプリケーションに取り組んでいる場合のみ。
miva2

8

サードパーティのライブラリに頼ることなく、Javaの標準に厳密に従ってURL検証を実行する方法があります。

boolean isValidURL(String url) {
  try {
    new URI(url).parseServerAuthority();
    return true;
  } catch (URISyntaxException e) {
    return false;
  }
}

これは有効なURI であるURIチェックのコンストラクタでありurl、への呼び出しparseServerAuthorityはそれがURL(絶対または相対)であり、URNではないことを確認します。


例外は、「このURIの機関コンポーネントが定義されているが、RFC 2396に従ってサーバーベースの機関として解析できない場合」にスローされます。これは他のほとんどの提案よりもはるかに優れていますが、URLを検証できません。
マーティン

@Martin、コンストラクタでの検証を忘れました。私が書いたように、URIコンストラクターの呼び出しと呼び出しの組み合わせは、単独parseServerAuthorityではなくURLを検証しますparseServerAuthority
dened

1
このページで、提案によって誤って検証された例を見つけることができます。ドキュメントを参照してください。意図した用途向けに設計されていない場合は、悪用するように宣伝しないでください。
マーティン

@マーティン、もっと具体的に言えますか?あなたの意見では、この方法で誤って検証された例はどれですか?
dened

1
@Asuはい。2番目://はホストの後に来:て、構文に従って空にすることができるポート番号を紹介します。//空のセグメントを持つパスの一部であり、これも有効です。ブラウザにこのアドレスを入力すると、ブラウザはそれを開こうとします(ただし、おそらくhttps;)という名前のサーバーが見つかりません)。
dened

2

URLオブジェクトが検証と接続の両方を処理することを指摘することが重要です。次に、sun.net.www.protocolでハンドラーが提供されているプロトコル(fileftpgopherhttphttpsjarmailtonetdoc)のみが有効なプロトコルです。たとえば、LDAPプロトコルで新しいURLを作成してみます。

new URL("ldap://myhost:389")

を取得しjava.net.MalformedURLException: unknown protocol: ldapます。

独自のハンドラを実装し、それをを介して登録する必要がありますURL.setURLStreamHandlerFactory()。URL構文を検証するだけの場合は、やりすぎです。正規表現の方が簡単なソリューションのようです。


1

システムプロパティとして正しいプロキシを使用していますか?

また、1.5または1.6を使用している場合は、java.net.ProxyインスタンスをopenConnection()メソッドに渡すことができます。これはよりエレガントなimoです。

//Proxy instance, proxy ip = 10.0.0.1 with port 8080
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("10.0.0.1", 8080));
conn = new URL(urlString).openConnection(proxy);

なぜこれがエレガントで正しいのでしょうか?動作時に高価なリソースを使用し、テスト時に正しいURLが接続に使用できないと動作しません。
マーティン

0

最良の応答はユーザー@ b1nary.atr0phyからのものだと思います。どういうわけか、可能なすべてのケースをカバーするために、b1nay.atr0phy応答からのメソッドを正規表現と組み合わせることをお勧めします。

public static final URL validateURL(String url, Logger logger) {

        URL u = null;
        try {  
            Pattern regex = Pattern.compile("(?i)^(?:(?:https?|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))\\.?)(?::\\d{2,5})?(?:[/?#]\\S*)?$");
            Matcher matcher = regex.matcher(url);
            if(!matcher.find()) {
                throw new URISyntaxException(url, "La url no está formada correctamente.");
            }
            u = new URL(url);  
            u.toURI(); 
        } catch (MalformedURLException e) {  
            logger.error("La url no está formada correctamente.");
        } catch (URISyntaxException e) {  
            logger.error("La url no está formada correctamente.");  
        }  

        return u;  

    }

1
この正規表現にはいくつかの問題があります。1.プレフィックスのないURLは無効です(例: "stackoverflow.com")。これには、プレフィックスがない場合に2つのサフィックスを持つURLも含まれます(例: "amazon.co.uk ")。2. IPは、プレフィックスを使用するかどうかに関係なく、常に無効です(「127.0.0.1」など)。"((http|https|ftp)://)?((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"source)の使用をお勧めします。この正規表現の唯一の欠点は、たとえば「127.0..0.1」と「12.7」が有効であることです。
ネフ

-2

ありがとう。NickDKによって提案されているようにプロキシを渡してURL接続を開くことは正常に機能します。

//Proxy instance, proxy ip = 10.0.0.1 with port 8080
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("10.0.0.1", 8080));
conn = new URL(urlString).openConnection(proxy);

ただし、前述のようにシステムプロパティは機能しません。

再度、感謝します。

よろしく、けや

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.