60 votes

Vérifier si l'URL existe en Ruby

Comment puis-je vérifier si une URL existe en utilisant Ruby ?

Par exemple, pour l'URL

https://google.com

le résultat devrait être véridique mais pour les URLs

https://no.such.domain

o

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

le résultat devrait être faux

0 votes

Vous devriez lire cet article : Validation des URL/URI en Ruby on Rails

9 votes

La question était suffisamment bonne pour correspondre à ma recherche google et les réponses sont précieuses

0 votes

Je suis d'accord. Cette question est utile.

74voto

Simone Carletti Points 77653

Utilisez le Net::HTTP bibliothèque.

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

A ce stade res es un Net::HTTPResponse objet contenant le résultat de la requête. Vous pouvez ensuite vérifier le code de réponse :

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

Note : Pour vérifier https basé sur l'url, use_ssl doit être true comme :

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)

0 votes

En production, pour chaque URL, je reçois un code 200 J'ai analysé les données suivantes http://www.http:/ cette URL et m'a donné 200 OK ... mais ce qui est faux ... Quel est le problème ici ? Une idée ? Note : Cela fonctionne bien sur l'Env. local.

0 votes

Pour vérifier également la partie requête, comme dans les urls de YouTube par exemple, utilisez address = [url.path, url.query].compact.split('').flatten.join('?') ou, avec Rails, [url.path.presence || '/', url.query.presence].compact.join('?') avant de faire req.request_head(address) .

62voto

fotanus Points 6322

Désolé pour la réponse tardive à cette question, mais je pense qu'elle mérite une meilleure réponse.

Il y a trois façons d'aborder cette question :

  1. Vérification stricte si l'URL existe
  2. Vérifiez si vous demandez l'URL correctement
  3. Vérifiez si vous pouvez le demander correctement et si le serveur peut y répondre correctement.

1. Vérification stricte de l'existence de l'URL

Alors que 200 signifie que le serveur répond à cette URL (donc, l'URL existe), répondre à un autre code de statut ne signifie pas que l'URL n'existe pas. Par exemple, répondre à 302 - redirected signifie que l'URL existe et qu'elle est redirigée vers une autre. Pendant la navigation, 302 se comporte souvent de la même manière que 200 à l'utilisateur final. Les autres codes d'état qui peuvent être renvoyés si une URL existe sont les suivants 500 - internal server error . Après tout, si l'URL n'existe pas, comment se fait-il que le serveur d'application ait traité votre demande au lieu de renvoyer tout simplement 404 - not found ?

Il n'y a donc en fait que deux cas où une URL n'existe pas : Lorsque le serveur n'existe pas ou lorsque le serveur existe mais ne trouve pas le chemin d'accès de l'URL donnée n'existe pas. Ainsi, le seul moyen de vérifier si l'URL existe est de vérifier si le serveur répond et si le code de retour n'est pas 404. C'est ce que fait le code suivant.

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. Vérifiez si vous demandez l'URL correctement

Cependant, La plupart du temps, nous ne sommes pas intéressés par l'existence d'une URL, mais par le fait de pouvoir y accéder. . Heureusement, en regardant le Codes d'état HTTP familles, c'est le 4xx qui indique une erreur du client (donc une erreur de votre part, ce qui signifie que vous ne demandez pas la page correctement, que vous n'avez pas la permission ou autre). C'est une bonne liste d'erreurs pour vérifier si vous pouvez accéder à cette page. De wiki :

La classe de code d'état 4xx est destinée aux cas où le client semble avoir commis une erreur. Sauf lorsqu'il répond à une demande HEAD, le serveur doit inclure une entité contenant une explication de la situation d'erreur, et préciser s'il s'agit d'une condition temporaire ou permanente. Ces codes d'état sont applicables à toute méthode de demande. Les agents utilisateurs doivent afficher toute entité incluse à l'utilisateur.

Ainsi, le code suivant Assurez-vous que l'URL existe et que vous pouvez y accéder. :

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. Vérifiez si vous pouvez le demander correctement et si le serveur peut y répondre correctement.

Tout comme le 4xx vérifie si vous pouvez accéder à l'URL, la famille 5xx La famille vérifie si le serveur a eu des difficultés à répondre à votre demande. La plupart du temps, une erreur dans cette famille est due à des problèmes sur le serveur lui-même, et nous espérons qu'ils sont en train de les résoudre. Si Vous devez être en mesure d'accéder à la page et d'obtenir une réponse correcte maintenant. vous devez vous assurer que la réponse ne provient pas de 4xx o 5xx et si vous avez été redirigé, la page redirigée répond correctement. De manière très similaire à (2), vous pouvez simplement utiliser le code suivant :

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

2 votes

Si vous faites cela avec https-urls, vous pourriez obtenir un Net::HTTPBadResponse: wrong status line erreur. C'est parce que vous devez dire à Net:HTTP d'utiliser ssl. Pour que cela fonctionne aussi pour https, mettez une ligne req.use_ssl = (url.scheme == 'https') avant d'appeler request_head

0 votes

@YoLudke Merci pour la contribution.

1 votes

Autre chose : si vous demandez (ou si une redirection va vers) ' exemple.com (sans le '/' de fin), vous obtenez alors un ArgumentError: HTTP request path is empty . Ce problème peut être résolu en modifiant le res = req.request_head(url.path) ligne vers path = url.path if url.path.present? y req.request_head(path || '/')

32voto

Turadg Points 3621

Net::HTTP fonctionne mais si vous pouvez travailler en dehors de stdlib, Faraday est meilleur.

Faraday.head(the_url).status == 200

(200 est un code de réussite, en supposant que c'est ce que vous vouliez dire par "existe").

8 votes

Pourquoi est-il meilleur à votre avis ?

2 votes

Vous pouvez également utiliser le Bibliothèque RestClient . require 'rest_client'; RestClient.head(url).code != 404

0 votes

Si vous voulez vérifier un simple "succès" général, vous pouvez aussi utiliser .success? . Cela donnera true pour tous les statuts de 200 a 299 et false pour tous les autres statuts. github.com/lostisland/faraday/search?q=SuccessfulStatuses

3voto

Sandro Munda Points 12808

Vous devriez lire cet article :

Validation des URL/URI en Ruby on Rails

3voto

Ryan Tate Points 671

La réponse de Simone m'a été très utile.

Voici une version qui renvoie vrai/faux selon la validité de l'URL, et qui gère les redirections :

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

0 votes

Que faire si le serveur ne prend pas en charge les demandes HEAD ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X