Java'da URL doğrulama


104

Java'da belirli bir URL'yi doğrulamak için herhangi bir standart API olup olmadığını bilmek istedim. Hem URL dizesinin doğru olup olmadığını, yani verilen protokolün geçerli olup olmadığını hem de bir bağlantının kurulup kurulamayacağını kontrol etmek istiyorum.

HttpURLConnection kullanmayı, URL'yi sağlamayı ve ona bağlanmayı denedim. İhtiyacımın ilk kısmı yerine getirilmiş gibi görünüyor ancak HttpURLConnection.connect () 'i gerçekleştirmeye çalıştığımda,' java.net.ConnectException: Bağlantı reddedildi 'istisnası atılıyor.

Bunun nedeni proxy ayarları olabilir mi? Proxy için Sistem özelliklerini ayarlamayı denedim, ancak başarı olmadı.

Neyi yanlış yaptığımı bana bildirin.


2
Burada 2 soru var gibi görünüyor; URL doğrulama ve ConnectException'ın nedenini bulma
Ben James

Bu, google'ın ilk java url validatorhedefi olduğu için , burada gerçekten de sorular var, url'nin nasıl doğrulanacağı (dizeye bakılarak) ve url'nin erişilebilir olup olmadığının nasıl kontrol edileceği (örneğin bir http bağlantısı aracılığıyla).
vikingsteve

Yanıtlar:


158

Topluluğun yararı için, bu ileti dizisi Google'da
" url doğrulayıcı java " arandığında en üst sırada yer aldığından


İstisnaları yakalamak pahalıdır ve mümkün olduğunda bundan kaçınılmalıdır. Yalnızca Dizenizin geçerli bir URL olduğunu doğrulamak istiyorsanız , Apache Commons Doğrulayıcı projesinden UrlValidator sınıfını kullanabilirsiniz .

Örneğin:

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

38
Bu URLValidator sınıfı, kullanımdan kaldırıldı olarak işaretlendi. Önerilen URLValidator, yordamlar paketindedir: commons.apache.org/validator/apidocs/org/apache/commons/…
Spektr

6
@Spektr Bağlantıyı düzelttim. Teşekkürler.
Yonatan

18
Bunun nasıl standart API
b1nary.atr0phy

2
UrlValidator'ın kendi bilinen sorunları vardır. Daha aktif olarak bakımı yapılan alternatif bir kütüphane var mı?
Alex Averbuch

9
@AlexAverbuch: UrlValidator ile ilgili sorunların ana hatlarını verebilir misiniz? Sadece var olduklarını söylemek ama ne olduklarını söylememek çok yardımcı olmaz.
cdmckay

33

Hem bir URLnesne hem de bir nesne oluşturmanız gerekir URLConnection. Aşağıdaki kod, hem URL biçimini hem de bir bağlantının kurulup kurulamayacağını test edecektir:

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
}

Hatalı biçimlendirilmiş url'leri / sorunları kontrol etmenin birden çok yolu olduğunu unutmayın. Örneğin, url'nizi a için kullanacaksanız new HttpGet(url), IllegalArgumentException HttpGet(...)hatalı biçimlendirilmiş bir url varsa atıkları yakalayabilirsiniz . Ve HttpResponseveri alma ile ilgili bir sorun varsa irade de sana şeyler atar.
Peter Ajtai

2
Bağlantı yalnızca ana bilgisayar kullanılabilirliğini doğrular. URL'nin geçerliliği ile ilgisi yoktur.
Andrey Rodionov

2
MalformedURLException, bir URL'nin geçerli biçimini test etmek için güvenli bir strateji değildir. Bu cevap yanıltıcıdır.
Martin

1
@Martin: Neden güvenli olmadığını açıklayabilir misin?
Jeroen Vannevel

28
Bu çok çok pahalıdır. openConnection / connect aslında http kaynağına bağlanmayı deneyecektir. Bu, bir URL'yi doğrulamak için şimdiye kadar gördüğüm en pahalı yollardan biri olmalı.
Glenn Bech

33

java.net.URLSınıf değildir hiç aslında URL'leri doğrulayarak iyi bir yoldur. MalformedURLExceptionolduğu değil inşaat sırasında tüm bozuk biçimli URL'ler üzerinde atılmış. Yakalamak IOExceptionüzerinde java.net.URL#openConnection().connect()URL ya tek bağlantı kurulabilir Hava olmadığını söylemek doğrulamaz.

Şu kod parçasını düşünün:

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

..hiçbir istisna atmaz.

Bağlamdan bağımsız bir dilbilgisi kullanılarak uygulanan bazı doğrulama API'lerini kullanmanızı veya çok basitleştirilmiş doğrulamada yalnızca normal ifadeleri kullanmanızı öneririm. Bununla birlikte, bunun için daha üstün veya standart bir API önerecek birine ihtiyacım var, daha yeni aramaya başladım.

NotURL#toURI() İstisnanın işlenmesiyle birlikte java.net. URISyntaxExceptionURL'lerin doğrulanmasını kolaylaştırabileceği önerilmiştir . Bununla birlikte, bu yöntem yalnızca yukarıdaki çok basit durumlardan birini yakalar.

Sonuç, URL'leri doğrulamak için standart bir java URL ayrıştırıcısı olmadığıdır.


Bu soruna bir çözüm buldunuz mu?
kidd0

@ bi0s.kidd0 Kullanılabilecek birkaç kitaplık var ama biz kendi kütüphanemizi oluşturmaya karar verdik. Tam değil, ancak etki alanlarını veya IP'leri (hem v4 hem de v6) içeren URL'ler de dahil olmak üzere ilgilendiğimiz şeyleri ayrıştırabilir. github.com/jajja/arachne
Martin

15

Yalnızca standart API kullanarak , dizeyi bir URLnesneye iletin ve ardından onu bir URInesneye dönüştürün . Bu, URL'nin geçerliliğini RFC2396 standardına göre doğru bir şekilde belirleyecektir.

Misal:

public boolean isValidURL(String url) {

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

    return true;
}

5
Bu dize-> url-> uri doğrulama şemasının bu test durumlarının geçerli olduğunu bildirdiğine dikkat edin: "http: //.com" " com ." "ftp: // :::: @ example.com" "http: /test.com" "http: test.com" "http: /:" Bu standart API olmasına rağmen, geçerli olduğu doğrulama kuralları ne beklenir.
DaveK

10

android.webkit.URLUtilAndroid'de kullanın :

URLUtil.isValidUrl(URL_STRING);

Not: Yalnızca URL'nin ilk şemasını kontrol ediyor, URL'nin tamamının geçerli olup olmadığını kontrol etmiyor.


2
Tabii bir android uygulaması üzerinde çalışıyorsanız.
miva2

8

Üçüncü taraf kitaplıklara başvurmadan Java'daki standartlara tam olarak uygun şekilde URL doğrulaması gerçekleştirmenin bir yolu vardır:

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

Geçerli bir URI olan URIdenetimlerin yapıcısı urlve parseServerAuthoritybunun bir URL (mutlak veya göreceli) ve bir URN değil olmasını sağlayan çağrı .


"Bu URI'nin yetki bileşeni tanımlanmışsa ancak RFC 2396'ya göre sunucu tabanlı bir yetki olarak ayrıştırılamıyorsa" istisna atılır. Bu, diğer birçok tekliften çok daha iyi olsa da, bir URL'yi doğrulayamaz.
Martin

@Martin, kurucudaki doğrulamayı unuttunuz. Yazdığım gibi, URIyapıcı çağrısı ve çağrının birleşimi parseServerAuthorityURL'yi doğrular, parseServerAuthoritytek başına değil .
dened

1
Bu sayfada, önerinizle yanlış bir şekilde doğrulanan örnekler bulabilirsiniz. Belgelere bakın ve amaçlanan kullanımınız için tasarlanmamışsa, lütfen bunları sömürmeye teşvik etmeyin.
Martin

@Martin, daha spesifik olabilir misin? Sizce hangi örnekler bu yöntemle yanlış olarak doğrulanmıştır?
dened

1
@Asu evet. İkincisi ://, ana bilgisayardan sonra gelir :, sözdizimine göre boş olabilen bağlantı noktası numarasını sunar. //aynı zamanda geçerli olan boş segmentli yolun bir parçasıdır. Bu adresi tarayıcınıza girerseniz, onu açmaya çalışacaktır (ancak büyük olasılıkla https; adlı sunucuyu bulamayacaktır ).
dened

2

URL nesnesinin hem doğrulamayı hem de bağlantıyı işlediğini belirtmek önemlidir. O halde, yalnızca sun.net'te bir işleyicinin sağlandığı protokoller yetkilidir ( dosya , ftp , gopher , http , https , jar , mailto , netdoc ) geçerlidir. Örneğin, ldap protokolü ile yeni bir URL oluşturmayı deneyin :

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

Bir java.net.MalformedURLException: unknown protocol: ldap.

Kendi işleyicinizi uygulamanız ve kaydettirmeniz gerekir URL.setURLStreamHandlerFactory(). Sadece URL sözdizimini doğrulamak istiyorsanız, bir regexp daha basit bir çözüm gibi görünüyor.


1

Sistem özellikleri olarak doğru proxy'yi kullandığınızdan emin misiniz?

Ayrıca 1.5 veya 1.6 kullanıyorsanız, bir java.net.Proxy örneğini openConnection () yöntemine iletebilirsiniz. Bu daha zarif bir 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);

Bu neden zarif ve hatta doğru olsun? Çalışırken pahalı kaynakları kullanır ve çalışmadığı için test edildiğinde bağlantı için doğru bir URL kullanılamaz.
Martin

0

En iyi yanıtın user @ b1nary.atr0phy olduğunu düşünüyorum. Her nasılsa, tüm olası durumları kapsamak için b1nay.atr0phy yanıtındaki yöntemi bir normal ifadeyle birleştirmenizi öneririm.

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
Bu normal ifadeyle ilgili birkaç sorun vardır: 1. Öneki olmayan URL'ler geçersizdir (ör. "Stackoverflow.com"), bu aynı zamanda önek eksikse iki son ek içeren URL'leri de içerir (ör. "Amazon.co.uk "). 2. Öneki kullansalar da kullanmasalar da IP'ler her zaman geçersizdir (örn. " 127.0.0.1" ). "((http|https|ftp)://)?((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"( Kaynak ) kullanmanızı öneririm . Bu normal ifadenin tek dezavantajı, örneğin "127.0..0.1" ve "127.0" ın geçerli olmasıdır.
Neph

-2

Teşekkürler. NickDK tarafından önerildiği gibi Proxy'yi geçerek URL bağlantısını açmak iyi çalışıyor.

//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);

Ancak sistem özellikleri daha önce bahsettiğim gibi çalışmıyor.

Tekrar teşekkürler.

Saygılarımızla, Keya

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.