EOFError: problème de fin de fichier atteint avec Net :: HTTP

158

J'utilise ruby-1.8.7-p302 / Rails 2.3.11. J'essaie d'utiliser FQL (API Facebook) pour obtenir des statistiques pour un lien. Voici mon code:

def stats(fb_post_url)
  url = BASE_URI + "?query=#{URI.encode("select like_count from link_stat where url=\"#{fb_post_url}\"")}"
  parsed_url = URI.parse(url)
  http = Net::HTTP.new(parsed_url.host, parsed_url.port)
  request = Net::HTTP::Get.new(parsed_url.request_uri)

  response = http.request(request)
  response.inspect
end

Et voici l'erreur:

EOFError: end of file reached
from /home/rahul/.rvm/rubies/ruby-1.8.7-p302/lib/ruby/1.8/net/protocol.rb:135:in `sysread'
from /home/rahul/.rvm/rubies/ruby-1.8.7-p302/lib/ruby/1.8/net/protocol.rb:135:in `rbuf_fill'
from /home/rahul/.rvm/rubies/ruby-1.8.7-p302/lib/ruby/1.8/timeout.rb:67:in `timeout'
from /home/rahul/.rvm/rubies/ruby-1.8.7-p302/lib/ruby/1.8/timeout.rb:101:in `timeout'
from /home/rahul/.rvm/rubies/ruby-1.8.7-p302/lib/ruby/1.8/net/protocol.rb:134:in `rbuf_fill'
from /home/rahul/.rvm/rubies/ruby-1.8.7-p302/lib/ruby/1.8/net/protocol.rb:116:in `readuntil'
from /home/rahul/.rvm/rubies/ruby-1.8.7-p302/lib/ruby/1.8/net/protocol.rb:126:in `readline'
from /home/rahul/.rvm/rubies/ruby-1.8.7-p302/lib/ruby/1.8/net/http.rb:2028:in `read_status_line'
from /home/rahul/.rvm/rubies/ruby-1.8.7-p302/lib/ruby/1.8/net/http.rb:2017:in `read_new'
from /home/rahul/.rvm/rubies/ruby-1.8.7-p302/lib/ruby/1.8/net/http.rb:1051:in `request'
from /home/rahul/.rvm/rubies/ruby-1.8.7-p302/lib/ruby/1.8/net/http.rb:1037:in `request'
from /home/rahul/.rvm/rubies/ruby-1.8.7-p302/lib/ruby/1.8/net/http.rb:543:in `start'
from /home/rahul/.rvm/rubies/ruby-1.8.7-p302/lib/ruby/1.8/net/http.rb:1035:in `request'
from /home/rahul/Work/Radr/lib/fb_stats.rb:13:in `stats'
from (irb):10

Cela ne semble se produire que dans le cas de l'API Facebook. De plus, je l'ai vu suggérer dans certains articles que cela pourrait être un bug dans Net :: HTTP.

Rahul Singh
la source
3
Avez-vous trouvé une solution pour cela? Je suis confronté à un problème similaire dans l'API SFDC.
Nilesh

Réponses:

281

Si l'URL utilise https au lieu de http, vous devez ajouter la ligne suivante:

parsed_url = URI.parse(url)
http = Net::HTTP.new(parsed_url.host, parsed_url.port)
http.use_ssl = true

Notez le supplément http.use_ssl = true.

Et le code plus approprié qui gérerait à la fois http et https sera similaire au suivant.

url = URI.parse(domain)
req = Net::HTTP::Post.new(url.request_uri)
req.set_form_data({'name'=>'Sur Max', 'email'=>'[email protected]'})
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = (url.scheme == "https")
response = http.request(req)

Voir plus dans mon blog: EOFError : problème de fin de fichier atteint lors de la publication d'un formulaire avec Net :: HTTP .

Sur Max
la source
Merci, cela m'a aidé à comprendre la différence entre httpet req.
guptron
6
Le lien de l'article de blog est rompu, mais essayez ceci: web.archive.org/web/20150429191916/http://expressica.com/2012/…
Henrik N
Et si ce n'est pas https?
Jwan622
5

J'ai eu un problème similaire avec une demande à un service non SSL.

Ce blog suggérait vaguement d'essayer d'encoder l'URI de l'URL qui est passée à 'get': http://www.loudthinking.org/2010/02/ruby-eoferror-end-of-file-reached.html

J'ai essayé, basé sur le désespoir, et dans mes tests limitatifs, cela semble l'avoir résolu pour moi. Mon nouveau code est:

@http = Net::HTTP.new('domain.com')  
@http = @http.start    
url = 'http://domain.com/requested_url?blah=blah&etc=1'
req = Net::HTTP::Get.new(URI.encode(url))
req.basic_auth USERNAME, API_KEY
res = @http.request(req) 

Notez que j'utilise @ http.start car je souhaite maintenir la session HTTP sur plusieurs requêtes. En dehors de cela, vous voudrez peut-être essayer la partie la plus pertinente qui est: URI.encode (url) dans l'appel get

Phil
la source
2
Je voulais juste fournir des commentaires supplémentaires à ce sujet, car cela semble toujours utile. J'utilise cet URI codé sur un serveur de production depuis 4 mois et je peux confirmer qu'il a résolu le problème.
Phil
3

Je trouve que je rencontre régulièrement des problèmes Net :: HTTP et Net :: FTP comme celui-ci, et quand je le fais, entourer l'appel avec un timeout () fait disparaître tous ces problèmes. Alors, où cela va parfois se bloquer pendant 3 minutes environ, puis déclencher une EOFError:

res = Net::HTTP.post_form(uri, args)

Cela résout toujours le problème pour moi:

res = timeout(120) { Net::HTTP.post_form(uri, args) }
Sean
la source
3

J'ai eu le même problème, ruby-1.8.7-p357, et j'ai essayé des tas de choses en vain ...

J'ai finalement réalisé que cela n'arrive que sur plusieurs appels en utilisant la même instance XMLRPC :: Client!

Alors maintenant, je ré-instancie mon client à chaque appel et cela fonctionne: |

jobwat
la source
1

Après avoir fait quelques recherches, cela se passait dans la XMLRPC::Clientbibliothèque de Ruby - qui utilise NET::HTTP. Le client utilise la start()méthode NET::HTTPqui maintient la connexion ouverte pour les demandes futures.

Cela s'est produit précisément 30 secondes après les dernières demandes - donc je suppose ici que le serveur sur lequel il se trouve ferme les demandes après cette heure. Je ne sais pas à quoi sert la valeur par défaut pour NET::HTTPgarder la demande ouverte - mais je suis sur le point de tester avec 60 secondes pour voir si cela résout le problème.

TJ Biddle
la source
1
Quel a été le résultat?
Peter Mortensen
1

J'ai rencontré cela récemment et j'ai finalement découvert que cela était dû à un délai d'expiration du réseau à partir du point de terminaison que nous frappions. Heureusement pour nous, nous avons pu augmenter la durée du timeout.

Pour vérifier que c'était notre problème (et en fait pas un problème avec net http), j'ai fait la même demande avec curl et j'ai confirmé que la demande était en cours de résiliation.

Tyler
la source
-1

Dans Ruby on Rails, j'ai utilisé ce code, et cela fonctionne parfaitement:

req_profilepic = ActiveSupport::JSON.decode(open(URI.encode("https://graph.facebook.com/me/?fields=picture&type=large&access_token=#{fb_access_token}")))

profilepic_url = req_profilepic['picture']
Nicolas Grenié
la source