Qual è la differenza tra URI.escape e CGI.escape?


147

Qual è la differenza tra URI.escapee CGI.escapee quale dovrei usare?

Risposte:


124

C'erano alcune piccole differenze, ma il punto importante è che URI.escapeè stato deprecato in Ruby 1.9.2 ... quindi usa CGI::escapeo ERB :: Util.url_encode .

C'è una lunga discussione su ruby-core per gli interessati che menziona anche WEBrick :: HTTPUtils.escape e WEBrick :: HTTPUtils.escape_form .


11
Solo per aggiungere confusione - ho appena visto un commento su stackoverflow.com/questions/4967608/… in cui qualcuno ha menzionato che la fuga cgi usa '+' invece di% 20 per gli spazi, e che è contro la 'specifica' ...
Louis Sayers,

18
è un'alternativa ERB::Util.url_encodeche utilizza correttamente %20 per gli spazi
riffraff

1
@Ernest: vedi: github.com/ruby/ruby/commit/… (risposta aggiornata)
Marc-André Lafortune

4
ruby-doc.org/stdlib-2.0.0/libdoc/uri/rdoc/URI/Escape.html . C'è il modulo URI.escape in ruby ​​2.0.0. Perché è stato deprecato?
user938363

1
@ user938363 se fai clic su Mostra sorgente lì vedrai che è ancora contrassegnato come obsoleto.
disegnato l'

229

Qual è la differenza tra un'ascia e una spada e quale dovrei usare? Bene dipende da cosa devi fare.

URI.escapedoveva codificare una stringa (URL) in, cosiddetta " codifica in percentuale ".

CGI::escapeproviene dalle specifiche CGI , che descrive come i dati dovrebbero essere codificati / decodificati tra il server Web e l'applicazione.

Ora, supponiamo che tu debba sfuggire a un URI nella tua app. È un caso d'uso più specifico. Per questo, la comunità di Ruby ha usato URI.escapeper anni. Il problema URI.escapeera che non poteva gestire le specifiche RFC-3896.

URI.escape 'http://google.com/foo?bar=at#anchor&title=My Blog & Your Blog' 
# => "http://google.com/foo?bar=at%23anchor&title=My%20Blog%20&%20Your%20Blog"

URI.escape è stato contrassegnato come obsoleto:

Inoltre l'attuale URI.encode è gsub semplice. Ma penso che dovrebbe dividere un URI in componenti, quindi sfuggire a ciascun componente e infine unirli.

Quindi l'attuale URI.encode è considerato dannoso e deprecato. Questo verrà rimosso o cambierà drasticamente il comportamento.

Qual è la sostituzione in questo momento?

Come ho detto sopra, il codice URI corrente è errato a livello di specifica. Quindi non forniremo la sostituzione esatta. La sostituzione varierà a seconda del suo caso d'uso.

https://bugs.ruby-lang.org/issues/4167

Sfortunatamente non c'è una sola parola al riguardo nei documenti, l'unico modo per saperlo è controllare la fonte, o eseguire lo script con avvertimenti a livello dettagliato ( -wW2) (o usare un po 'di Google-Fu).

Alcuni hanno proposto di utilizzare CGI::Escapeper i parametri della query, poiché non è stato possibile sfuggire a un intero URI:

CGI::escape 'http://google.com/foo?bar=at#anchor&title=My Blog & Your Blog'
# => "http%3A%2F%2Fgoogle.com%2Ffoo%3Fbar%3Dat%23anchor%26title%3DMy+Blog+%26+Your+Blog"

CGI::escapedovrebbe essere usato solo per i parametri della query, ma i risultati saranno, ancora una volta, contro la specifica. In realtà il caso d'uso più comune è l'escaping dei dati del modulo, ad esempio durante l'invio di una application/x-www-form-urlencodedrichiesta POST.

Anche menzionato WEBrick::HTTPUtils.escapenon è molto di miglioramento (di nuovo è solo gsubun'opzione semplice , che è, IMO, anche peggiore di URI.escape):

WEBrick::HTTPUtils.escape 'http://google.com/foo?bar=at#anchor&title=My Blog & Your Blog'
# => "http://google.com/foo?bar=at%23anchor&title=My%20Blog%20&%20Your%20Blog" 

Il più vicino alla specifica sembra essere la gemma indirizzabile :

require 'addressable/uri'
Addressable::URI.escape 'http://google.com/foo?bar=at#anchor&title=My Blog & Your Blog'
# => "http://google.com/foo?bar=at#anchor&title=My%20Blog%20&%20Your%20Blog"

Si noti che, a differenza di tutte le opzioni precedenti, Indirizzabile non sfugge #e questo è il comportamento previsto. vuoi mantenere l' #hash nel percorso URI ma non nella query URI.

L'unico problema rimasto è che non abbiamo evitato correttamente i nostri parametri di query, il che ci porta alla conclusione: non dovremmo usare un singolo metodo per l'intero URI, perché non esiste una soluzione perfetta (finora). Come vedi &non è stato eliminato da "Il mio blog e il tuo blog". Dobbiamo utilizzare una diversa forma di escape per i parametri della query, in cui gli utenti possono inserire caratteri diversi che hanno un significato speciale negli URL. Inserisci la codifica URL. La codifica URL deve essere utilizzata per ogni valore di query "sospetto", in modo simile a quanto ERB::Util.url_encodesegue:

ERB::Util.url_encode "My Blod & Your Blog"
# => "My%20Blod%20%26%20Your%20Blog""

È bello ma abbiamo già richiesto Indirizzabile:

uri = Addressable::URI.parse("http://www.go.com/foo")
# => #<Addressable::URI:0x186feb0 URI:http://www.go.com/foo>
uri.query_values = {title: "My Blog & Your Blog"}
uri.normalize.to_s
# => "http://www.go.com/foo?title=My%20Blog%20%26%20Your%20Blog"

Conclusione:

  • Non usare URI.escapeo simili
  • Utilizzare CGI::escapese è necessario solo il modulo di escape
  • Se devi lavorare con URI, usa Indirizzabile, offre la codifica URL, la codifica dei moduli e normalizza gli URL.
  • Se si tratta di un progetto Rails, controlla " Come si esegue l'escape dell'URL di una stringa in Rails? "

Grazie mille per l'informazione. Si è sicuramente sbarazzato di alcuni avvisi di test della zappa. Di seguito un rastrello e una zappa.
Douglas G. Allen,

Grande spiegazione @Ernest, ma il problema è che non funzionerà con URL esterni che non sto cercando di creare (e su cui non ho alcun controllo). ad es. crawler che legge gli URL da una pagina Web e quindi tenta di accedere a tali URL (che devono essere codificati prima dell'accesso).
amit_saxena,

@amit_saxena se puoi permetterti di avere Addressableuna delle tue gemme, puoi prima analizzare l'URL, fi rubydoc.info/gems/addressable/Addressable/URI.heuristic_parse
Ernest

Interessante! Ma ancora una volta, non riesco a ottenere un hash di parametri dall'URL originale usando questo, che codifico come descrivi. Il flusso nel mio caso è: ottengo URL esterni da alcuni feed -> che quindi devo codificare -> Passa al client http per recuperare il contenuto. Ora, se non codifico correttamente gli URL esterni, i client HTTP basati su ruby ​​falliscono con errori URI non validi.
amit_saxena,

Il metodo di analisi @amit_saxena restituirà l'istanza di Addressable:URL, è quindi possibile chiamare tutti i metodi di istanza su di esso, forse uno di loro ti darà i risultati desiderati: rubydoc.info/gems/addressable/Addressable/URI
Ernest


6

CGI::escapeè utile per sfuggire al segmento di testo in modo che possano essere utilizzati nei parametri della query url (stringhe dopo '?'). Ad esempio, se si desidera avere un parametro contenente caratteri di barra nell'URL, è necessario prima CGI :: escape quella stringa e quindi inserirlo nell'URL.

Tuttavia in Rails probabilmente non lo utilizzerai direttamente. Di solito si utilizza hash.to_param, che verrà utilizzato CGI::escapesotto il cofano.


URI::escapeè buono per sfuggire a un URL che non è stato evaso correttamente. Ad esempio, alcuni siti Web generano URL errati / senza escape nel loro tag di ancoraggio. Se il tuo programma utilizza questi URL per recuperare più risorse, OpenURI si lamenterà che gli URL non sono validi. Hai bisogno di URI::escapequesti per renderlo un URL valido. Quindi viene utilizzato per sfuggire all'intera stringa URI per renderlo corretto. Nella mia parola URI :: unescape rende un url leggibile da umano e URI :: escape lo rende valido per i browser.

Questi sono i termini del mio profano e sono libero di correggerli.


1

La differenza è che URI.escape non funziona ...

CGI.escape"/en/test?asd=qwe"
=> "%2Fen%2Ftest%3Fasd%3Dqwe"

URI.escape"/en/test?asd=qwe"
=> "/en/test?asd=qwe"

2
Hai scelto il test case sbagliato. Gli / 's,?' E = = fanno tutti parte di un URI valido e quindi non sono salvati. Dovrebbero essere presenti altri caratteri che devono essere sottoposti a escape soprattutto nella stringa di query.
Gerard ONeill,

@GerardONeill Ho scelto il test case proprio per mostrare come URI.escape non funziona e non è affidabile. Stai suggerendo che URI.escape sta eseguendo l'escape solo della stringa di query? come potrebbe sapere quando termina il valore di un parametro se voglio codificare un & in? forse è per questo che è obsoleto?
Radu Simionescu,

1
Questo è esattamente quello che sto dicendo. L'escape URI deve analizzare l'URL, separare ciò che pensa siano i singoli parametri, sfuggirli e rimetterli insieme. Anche quello può essere disordinato. Ma non lo fa - evita semplicemente di sfuggire ad alcuni personaggi mentre sfugge al resto, il che lo rende incompleto. Può essere usato per casi semplici, specialmente se sai che i tuoi parametri non saranno ... confusi.
Gerard ONeill,

0

CGI.escape serve per sfuggire a un valore URL nella stringa di query. Tutti i personaggi che non rientrano in ALPHA, DIGIT, '_', '-', '.' e '' il set di caratteri è evaso.

Ma ciò renderebbe un URL errato, dal momento che un URL deve avere '/', ':', '?', '[', '&', '=', E ';'. Forse di più a cui non riesco a pensare dalla parte superiore della mia testa.

URI.escape lascia soli quei caratteri URL e cerca di scappare dalle chiavi e dai valori della stringa di query. Tuttavia, questo non può davvero dipendere dal fatto che i valori possono avere tutti i tipi di caratteri che impediscono una facile fuga. Fondamentalmente, è troppo tardi. Ma se si può fare affidamento sull'URL come semplice (nessun valore '&' e '=' ecc. Nei valori), questa funzione potrebbe essere utilizzata per sfuggire a caratteri forse illeggibili o illegali.

In generale, usa sempre CGI.escape sulle singole chiavi e valori prima di unirli con '&' e aggiungerli dopo '?'.


0

CGI.escape non ha funzionato con l'API OpenProject. Ha codificato il [] ,: e non il +. Ho hackerato questo insieme che sembra funzionare finora per l'API di OpenProject. Ma sono sicuro che manchi alcuni .gsub. Probabilmente è quasi cattivo come URI.escape, ma non ti darà gli errori obsoleti.

class XXX
      def self.encode(path)
        path, query = path.split("?", 2)
        return path if query.nil?
        query = CGI.escape(query).gsub("%3A", ":").gsub("%3D","=").gsub("%5B","[").gsub("%5D","]").gsub("%2C",",").gsub("+","%20")
        return [path,query].join("?")
      end
end

XXX.encode("http://test.com/some/path?query=[box: \"cart\"]")
URI.encode("http://test.com/some/path?query=[box: \"cart\"]")

Entrambe le uscite:

=> " http://test.com/some/path?query=[box:%20%22cart%22] "
=> " http://test.com/some/path?query=[box:%20 % 22cart% 22] "

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.