Memvalidasi URL di Java


103

Saya ingin tahu apakah ada API standar di Java untuk memvalidasi URL tertentu? Saya ingin memeriksa apakah string URL sudah benar yaitu protokol yang diberikan valid dan kemudian untuk memeriksa apakah sambungan dapat dibuat.

Saya mencoba menggunakan HttpURLConnection, memberikan URL dan menghubungkannya. Bagian pertama dari persyaratan saya tampaknya terpenuhi tetapi ketika saya mencoba untuk melakukan HttpURLConnection.connect (), 'java.net.ConnectException: Pengecualian koneksi ditolak' dilempar.

Mungkinkah ini karena pengaturan proxy? Saya mencoba mengatur properti Sistem untuk proxy tetapi tidak berhasil.

Beri tahu saya apa yang saya lakukan salah.


2
Sepertinya ada 2 pertanyaan di sini; Validasi URL dan menemukan penyebab ConnectException
Ben James

Karena ini yang pertama kali dipukul google java url validator, memang ada pertanyaan di sini, bagaimana memvalidasi url (dari melihat string) dan bagaimana memeriksa apakah url dapat dijangkau (melalui koneksi http, misalnya).
vikingsteve

Jawaban:


157

Untuk kepentingan komunitas, karena utas ini berada di puncak di Google saat mencari
" url validator java "


Menangkap pengecualian itu mahal, dan harus dihindari bila memungkinkan. Jika Anda hanya ingin memverifikasi String Anda adalah URL yang valid, Anda dapat menggunakan kelas UrlValidator dari proyek Apache Commons Validator .

Sebagai contoh:

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
Kelas URLValidator itu ditandai tidak berlaku lagi. URLValidator yang direkomendasikan ada dalam paket rutinitas: commons.apache.org/validator/apidocs/org/apache/commons/…
Spektr

6
@Spektr Saya telah memperbaiki tautannya. Terima kasih.
Yonatan

18
Saya gagal untuk melihat bagaimana ini adalah API standar
b1nary.atr0phy

2
UrlValidator memiliki kumpulan masalah yang diketahui sendiri. Apakah ada perpustakaan alternatif yang dipertahankan dengan lebih aktif?
Alex Averbuch

9
@AlexAverbuch: dapatkah Anda menjelaskan masalah apa yang ada pada UrlValidator? Tidaklah terlalu membantu untuk hanya mengatakan mereka ada tetapi tidak mengatakan apa adanya.
cdmckay

33

Anda perlu membuat URLobjek dan URLConnectionobjek. Kode berikut akan menguji format URL dan apakah koneksi dapat dibuat:

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
}

Perhatikan bahwa ada beberapa cara untuk memeriksa format url / masalah yang salah. Misalnya, jika Anda akan menggunakan url untuk a new HttpGet(url), Anda dapat menangkap IllegalArgumentException HttpGet(...)lemparan jika ada format url yang salah. Dan HttpResponseakan melempar barang ke Anda juga jika ada masalah dengan mendapatkan data.
Peter Ajtai

2
Koneksi hanya memvalidasi ketersediaan host. Tidak ada hubungannya dengan validitas URL.
Andrey Rodionov

2
MalformedURLException bukanlah strategi yang aman untuk menguji bentuk URL yang valid. Jawaban ini menyesatkan.
Martin

1
@ Martin: dapatkah Anda menjelaskan mengapa ini tidak aman?
Jeroen Vannevel

28
Ini sangat, sangat mahal. openConnection / connect sebenarnya akan mencoba untuk terhubung ke sumber daya http. Ini pasti salah satu cara termahal yang pernah saya lihat untuk memverifikasi URL.
Glenn Bech

33

The java.net.URLkelas pada kenyataannya tidak sama sekali cara yang baik untuk memvalidasi URL. MalformedURLExceptionadalah tidak dilemparkan pada semua URL cacat selama konstruksi. Penangkapan IOExceptionatas java.net.URL#openConnection().connect()tidak memvalidasi URL baik, hanya memberitahu cuaca atau tidak koneksi dapat dibentuk.

Pertimbangkan bagian kode ini:

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

..yang tidak memberikan pengecualian apa pun.

Saya merekomendasikan menggunakan beberapa API validasi yang diimplementasikan menggunakan tata bahasa bebas konteks, atau dalam validasi yang sangat disederhanakan, cukup gunakan ekspresi reguler. Namun saya membutuhkan seseorang untuk menyarankan API superior atau standar untuk ini, saya baru saja mulai mencarinya sendiri.

Catatan Telah disarankan bahwa URL#toURI()kombinasi dengan penanganan pengecualian java.net. URISyntaxExceptiondapat memfasilitasi validasi URL. Namun, metode ini hanya menangkap salah satu kasus yang sangat sederhana di atas.

Kesimpulannya adalah tidak ada pengurai URL java standar untuk memvalidasi URL.


Sudahkah Anda menemukan solusi untuk masalah ini ??
kidd0

@ bi0s.kidd0 Ada beberapa pustaka yang dapat digunakan, tetapi kami memutuskan untuk menggulungnya sendiri. Ini tidak lengkap, tetapi dapat mengurai apa yang kami minati, termasuk URL yang berisi domain atau IP (baik v4 dan v6). github.com/jajja/arachne
Martin

15

Menggunakan hanya standar API, lulus string ke URLobjek kemudian dikonversi ke sebuah URIobjek. Ini secara akurat akan menentukan validitas URL sesuai dengan standar RFC2396.

Contoh:

public boolean isValidURL(String url) {

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

    return true;
}

5
Perhatikan bahwa skema validasi string-> url-> uri ini melaporkan bahwa kasus pengujian ini valid: "http: //.com" " com ." "ftp: // :::: @ example.com" "http: /test.com" "http: test.com" "http: /:" Jadi meskipun ini adalah API standar, aturan validasi yang diterapkannya mungkin tidak apa yang diharapkan.
DaveK

10

Gunakan android.webkit.URLUtildi android:

URLUtil.isValidUrl(URL_STRING);

Catatan: Ini hanya memeriksa skema awal URL, bukan seluruh URL valid.


2
Hanya jika Anda sedang mengerjakan aplikasi android tentunya.
miva2

8

Ada cara untuk melakukan validasi URL sesuai dengan standar di Java tanpa menggunakan pustaka pihak ketiga:

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

Konstruktor URIpemeriksaan yang urlmerupakan URI yang valid, dan panggilan untuk parseServerAuthoritymemastikan bahwa itu adalah URL (absolut atau relatif) dan bukan URN.


Pengecualian muncul "Jika komponen otoritas URI ini ditentukan tetapi tidak dapat diurai sebagai otoritas berbasis server menurut RFC 2396". Meskipun ini jauh lebih baik daripada kebanyakan proposal lainnya, ini tidak dapat memvalidasi URL.
Martin

@Martin, Anda lupa tentang validasi di konstruktor. Seperti yang saya tulis, kombinasi URIpanggilan konstruktor dan parseServerAuthoritypanggilan memvalidasi URL, tidak parseServerAuthoritysendirian.
dened

1
Anda dapat menemukan contoh di halaman ini yang salah divalidasi oleh saran Anda. Lihat dokumentasi, dan jika tidak dirancang untuk tujuan penggunaan Anda, jangan promosikan untuk mengeksploitasinya.
Martin

@ Martin, Bisakah Anda lebih spesifik? Contoh manakah menurut Anda yang salah divalidasi dengan metode ini?
dened

1
@Aya. Yang kedua ://muncul setelah host, :memperkenalkan nomor port, yang dapat dikosongkan menurut sintaks. //adalah bagian dari jalur dengan segmen kosong, yang juga valid. Jika Anda memasukkan alamat ini ke browser Anda, maka browser akan mencoba membukanya (tetapi kemungkinan besar tidak akan menemukan server bernama https;)).
dened

2

Penting untuk diketahui bahwa objek URL menangani validasi dan koneksi. Kemudian, hanya protokol yang penangannya telah disediakan di sun.net.www.protocol yang diotorisasi ( file , ftp , gopher , http , https , jar , mailto , netdoc ) adalah yang valid. Misalnya, coba buat URL baru dengan protokol ldap :

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

Anda akan mendapatkan file java.net.MalformedURLException: unknown protocol: ldap.

Anda perlu menerapkan penangan Anda sendiri dan mendaftarkannya URL.setURLStreamHandlerFactory(). Terlalu berlebihan jika Anda hanya ingin memvalidasi sintaks URL, regexp tampaknya merupakan solusi yang lebih sederhana.


1

Apakah Anda yakin Anda menggunakan proxy yang benar sebagai properti sistem?

Juga jika Anda menggunakan 1.5 atau 1.6 Anda bisa meneruskan instance java.net.Proxy ke metode openConnection (). Ini lebih elegan 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);

Mengapa ini elegan atau bahkan benar? Ini menggunakan sumber daya yang mahal saat berfungsi, dan tidak berfungsi karena URL yang benar tidak tersedia untuk koneksi saat diuji.
Martin

0

Saya pikir tanggapan terbaik adalah dari pengguna @ b1nary.atr0phy. Entah bagaimana, saya sarankan untuk menggabungkan metode dari respons b1nay.atr0phy dengan regex untuk mencakup semua kemungkinan kasus.

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
Ada beberapa masalah dengan regex ini: 1. URL tanpa awalan tidak valid, (mis. "Stackoverflow.com"), ini juga menyertakan URL dengan dua sufiks jika tidak memiliki awalan (mis. "Amazon.co.uk "). 2. IP selalu tidak valid (misalnya " 127.0.0.1" ), tidak peduli apakah mereka menggunakan awalan atau tidak. Saya sarankan menggunakan "((http|https|ftp)://)?((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"( sumber ). Satu-satunya downside ke regex ini adalah bahwa misalnya "127.0..0.1" dan "127.0" valid.
Nef

-2

Terima kasih. Membuka koneksi URL dengan meneruskan Proxy seperti yang disarankan oleh NickDK berfungsi dengan baik.

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

Properti sistem namun tidak berfungsi seperti yang saya sebutkan sebelumnya.

Terima kasih lagi.

Salam, Keya

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.