Verifica se l’URL esiste in Ruby

Come posso verificare se esiste un URL utilizzando Ruby?

Ad esempio, per l’URL

https://google.com 

il risultato dovrebbe essere vero , ma per gli URL

 https://no.such.domain 

o

 https://stackoverflow.com/no/such/path 

il risultato dovrebbe essere falso

Utilizzare la libreria Net :: HTTP .

 require "net/http" url = URI.parse("http://www.google.com/") req = Net::HTTP.new(url.host, url.port) res = req.request_head(url.path) 

res è un object Net :: HTTPResponse contenente il risultato della richiesta. È quindi ansible controllare il codice di risposta:

 do_something_with_it(url) if res.code == "200" 

Nota : per verificare l’url basato su https , use_ssl attributo use_ssl dovrebbe essere true come:

 require "net/http" url = URI.parse("https://www.google.com/") req = Net::HTTP.new(url.host, url.port) req.use_ssl = true res = req.request_head(url.path) 

Ci scusiamo per la risposta tardiva su questo, ma penso che questo meriti una risposta migliore.

Ci sono tre modi per guardare questa domanda:

  1. Controllo rigoroso se l’URL esiste
  2. Controlla se stai richiedendo la correzione dell’URL
  3. Verifica se è ansible richiederlo correttamente e il server può rispondere correttamente

1. Controllo rigoroso se l’URL esiste

Mentre 200 indica che il server risponde a tale URL (quindi, l’URL esiste), la risposta ad altri codici di stato non significa che l’URL non esiste. Ad esempio, rispondere a 302 - redirected significa che l’URL esiste e sta reindirizzandoti a un altro. Durante la navigazione, 302 molte volte si comporta allo stesso modo di 200 per l’utente finale. Altro codice di stato che può essere restituito se esiste un URL è 500 - internal server error . Dopotutto, se l’URL non esiste, come viene elaborato il server delle applicazioni la tua richiesta invece restituisce semplicemente 404 - not found ?

Quindi in realtà esiste un solo caso in cui un URL non esiste: quando il server non esiste o quando il server esiste ma non riesce a trovare il percorso URL specificato non esiste. Pertanto, l’unico modo per verificare se l’URL esiste è controllare se il server risponde e il codice di ritorno non è 404. Il seguente codice fa proprio questo.

 require "net/http" def url_exist?(url_string) url = URI.parse(url_string) req = Net::HTTP.new(url.host, url.port) req.use_ssl = (url.scheme == 'https') path = url.path if url.path.present? res = req.request_head(path || '/') res.code != "404" # false if returns 404 - not found rescue Errno::ENOENT false # false if can't find the server end 

2. Controlla se stai richiedendo il corretto URL

Tuttavia, la maggior parte delle volte non siamo interessati a vedere se esiste un URL, ma se possiamo accedervi . Fortunatamente guardando alle famiglie dei codici di stato HTTP , questa è la famiglia 4xx , che indica l’errore del client (quindi, un errore nella tua parte, il che significa che non stai richiedendo la pagina correttamente, non hai il permesso o qualsiasi altra cosa). Questo è un bene di errori per verificare se è ansible accedere a questa pagina. Dalla wiki:

La class 4xx del codice di stato è intesa per i casi in cui il client sembra aver commesso un errore. Tranne quando si risponde a una richiesta HEAD, il server deve includere un’entity framework che contiene una spiegazione della situazione di errore e se si tratta di una condizione temporanea o permanente. Questi codici di stato sono applicabili a qualsiasi metodo di richiesta. I programmi utente dovrebbero mostrare qualsiasi quadro inclusa all’utente.

Quindi il codice seguente si assicura che l’URL esista e tu possa accedervi :

 require "net/http" def url_exist?(url_string) url = URI.parse(url_string) req = Net::HTTP.new(url.host, url.port) req.use_ssl = (url.scheme == 'https') path = url.path if url.path.present? res = req.request_head(path || '/') if res.kind_of?(Net::HTTPRedirection) url_exist?(res['location']) # Go after any redirect and make sure you can access the redirected URL else res.code[0] != "4" #false if http code starts with 4 - error on your side. end rescue Errno::ENOENT false #false if can't find the server end 

3. Verifica se è ansible richiederlo correttamente e il server può rispondere correttamente

Proprio come la famiglia 4xx controlla se è ansible accedere all’URL, la famiglia 5xx controlla se il server ha avuto problemi nel rispondere alla richiesta. Un errore su questa famiglia il più delle volte sono problemi dovuti sul server stesso, e speriamo che stiano lavorando per risolverlo. Se è necessario essere in grado di accedere alla pagina e ottenere una risposta corretta ora , è necessario assicurarsi che la risposta non 4xx dalla famiglia 4xx o 5xx e, se è stato reindirizzato, la pagina reindirizzata risponde correttamente. Così simile a (2), puoi semplicemente usare il seguente codice:

 require "net/http" def url_exist?(url_string) url = URI.parse(url_string) req = Net::HTTP.new(url.host, url.port) req.use_ssl = (url.scheme == 'https') path = url.path if url.path.present? res = req.request_head(path || '/') if res.kind_of?(Net::HTTPRedirection) url_exist?(res['location']) # Go after any redirect and make sure you can access the redirected URL else ! %W(4 5).include?(res.code[0]) # Not from 4xx or 5xx families end rescue Errno::ENOENT false #false if can't find the server end 

Net::HTTP funziona ma se riesci a lavorare fuori da stdlib, Faraday è migliore.

 Faraday.head(the_url).status == 200 

(200 è un codice di successo, assumendo che ciò che intendevi per “esiste”.)

Dovresti leggere questo articolo:

Convalida URL / URI in Ruby on Rails

La risposta di Simone è stata molto utile per me.

Ecco una versione che restituisce true / false in base alla validità dell’URL e che gestisce i reindirizzamenti:

 require 'net/http' require 'set' def working_url?(url, max_redirects=6) response = nil seen = Set.new loop do url = URI.parse(url) break if seen.include? url.to_s break if seen.size > max_redirects seen.add(url.to_s) response = Net::HTTP.new(url.host, url.port).request_head(url.path) if response.kind_of?(Net::HTTPRedirection) url = response['location'] else break end end response.kind_of?(Net::HTTPSuccess) && url.to_s end