2013-07-03 2 views
9

Ich verwende derzeit OpenURI, um eine Datei in Ruby herunterzuladen. Leider scheint es unmöglich, die HTTP-Header zu erhalten, ohne die vollständige Datei herunterzuladen:So erhalten Sie HTTP-Header vor dem Download mit OpenUri von Ruby

open(base_url, 
    :content_length_proc => lambda {|t| 
    if t && 0 < t 
     pbar = ProgressBar.create(:total => t) 
    end 
    }, 
    :progress_proc => lambda {|s| 
    pbar.progress = s if pbar 
    }) {|io| 
    puts io.size 
    puts io.meta['content-disposition'] 
    } 

den Code oben Laufen zeigt, dass es zuerst die vollständige Datei herunterlädt und druckt nur dann die Header ich brauche.

Gibt es eine Möglichkeit, die Header zu erhalten, bevor die vollständige Datei heruntergeladen wird, damit ich den Download abbrechen kann, wenn die Header nicht so sind, wie ich es erwarte?

+0

duplizieren? http://stackoverflow.com/questions/13916046/display-http-headers-using-openuri?rq=1 – yeyo

+3

@Kira nein, mit der verknüpften Antwort wird zuerst herunterladen die vollständige Datei, genau das, was ich _not_ wollte. – ePirat

Antwort

4

Es scheint, was ich wollte, ist nicht möglich mit OpenURI archieve, zumindest nicht, wie ich schon sagte, ohne zuerst die ganze Datei zu laden.

ich war in der Lage zu tun, was ich Net :: HTTP ist request_get

Hier ein Beispiel unter Verwendung gesucht:

http.request_get('/largefile.jpg') {|response| 
    if (response['content-length'] < max_length) 
    response.read_body do |str| # read body now 
     # save to file 
    end 
    end 
} 

Beachten Sie, dass dies nur funktioniert, wenn ein Block mit, es zu tun mögen:

response = http.request_get('/largefile.jpg') 

der Körper wird bereits gelesen.

+0

Korrekt, liest OpenURI den Inhalt vor und gibt dann einen Datei-Handle zurück, ob Sie das Block-Formular verwenden oder nicht. –

11

können Sie Net verwenden :: HTTP für diese Angelegenheit, zum Beispiel:

require 'net/http' 

http = Net::HTTP.start('stackoverflow.com') 

resp = http.head('/') 
resp.each { |k, v| puts "#{k}: #{v}" } 
http.finish 

Ein weiteres Beispiel, diesmal den Header des wunderbaren Buchs bekommen, Object Orient Programmieren mit ANSI-C:

require 'net/http' 

http = Net::HTTP.start('www.planetpdf.com') 

resp = http.head('/codecuts/pdfs/ooc.pdf') 
resp.each { |k, v| puts "#{k}: #{v}" } 
http.finish 
+1

Es ist sauberer, die Blockform von 'start' zu verwenden. Siehe das Beispiel in [der Dokumentation] (http://ruby-doc.org/stdlib-2.0/libdoc/net/http/rdoc/Net/HTTP.html#method-i-head). –

+0

+1 @theTinMan. Hält es sauber (mit Links zu rdoc). – orde

+1

@theTinMan Verzeihung, aber das bedeutet nicht, dass ich die Existenz dieser Form nicht kenne, wie der Verweis auf die Referenz nahelegt. Ja, es ist sauberer, wenn man die Blockform benutzt, aber es bedeutet nicht "Perfektion", manchmal wird die Einrückung zu tief oder einfach die Blockform passt nicht so gut, es hängt von der Situation ab. – yeyo

2

Anstatt Net :: HTTP zu verwenden, das kann sein, als würde man einen Pool am Strand mit einer Sandschaufel graben, kann man eine Reihe von HTTP-Clients für Ruby verwenden und den Code aufräumen.

Hier ist eine Probe HTTParty mit:

require 'httparty' 

resp = HTTParty.head('http://example.org') 
resp.headers 
# => {"accept-ranges"=>["bytes"], "cache-control"=>["max-age=604800"], "content-type"=>["text/html"], "date"=>["Thu, 02 Mar 2017 18:52:42 GMT"], "etag"=>["\"359670651\""], "expires"=>["Thu, 09 Mar 2017 18:52:42 GMT"], "last-modified"=>["Fri, 09 Aug 2013 23:54:35 GMT"], "server"=>["ECS (oxr/83AB)"], "x-cache"=>["HIT"], "content-length"=>["1270"], "connection"=>["close"]} 

An diesem Punkt ist es einfach, die Größe des Dokuments zu überprüfen:

resp.headers['content-length'] # => "1270" 

Leider ist die HTTPd Sie reden vielleicht nicht wissen, wie groß wird der Inhalt sein; Um schnell reagieren zu können, berechnen die Server nicht unbedingt die Größe der dynamisch generierten Ausgabe, die fast genauso lang und fast so CPU-intensiv wäre wie das eigentliche Senden. Daher ist der Wert "content-length" möglicherweise fehlerhaft.

Das Problem mit Net :: HTTP ist, dass es nicht automatisch Weiterleitungen behandelt, also müssen Sie zusätzlichen Code hinzufügen. Zugegeben, dieser Code ist in der Dokumentation enthalten, aber der Code wächst weiter, da Sie mehr Dinge tun müssen, bis Sie schließlich einen weiteren HTTP-Client (YAHC) geschrieben haben. Vermeiden Sie das und verwenden Sie ein vorhandenes Rad.

+0

Wenn ich den Code richtig verstehe, tut dies tatsächlich eine HEAD-Anfrage, was in diesem speziellen Fall nicht das ist, was ich wollte. Auch wenn das im Allgemeinen wahrscheinlich eine gute Lösung wäre, musste ich in diesem Fall eine GET-Anfrage verwenden. – ePirat

+0

Ein GET wird immer versuchen, die gesamte Datei abzurufen. Es ist möglich, in die Verarbeitung zu gelangen und die Verbindung abzubrechen, aber das ist kein guter Netzwerk-Bürger. Überlegen Sie, was passiert: Sie geben ein GET aus, und der Server lädt die Datei, um mit dem Senden zu beginnen. Sie brechen ab, und Sie haben gerade zusätzliche Belastung für den Server und das dazwischen liegende Netzwerk und Ihren Host verursacht. Deshalb wurde HEAD erfunden, um das zu vermeiden. –

+0

Wie gesagt, mir ist das bekannt, aber im speziellen Fall funktionierte HEAD nicht, also war GET die einzige Option. Und ich wollte vermeiden, die ganze Datei herunterzuladen, nur um sie wegzuwerfen, also dachte ich, es wäre gut, wenn ich so früh wie möglich abbrechen könnte, nicht nachdem ich die ganze Datei heruntergeladen habe. – ePirat

Verwandte Themen