Was ist der Unterschied zwischen URI.escape und CGI.escape?

147

Was ist der Unterschied zwischen URI.escapeund CGI.escapeund welchen soll ich verwenden?

Tom Lehman
quelle

Antworten:

124

Es gab einige kleine Unterschiede, aber der wichtige Punkt ist, dass URI.escapeer in Ruby 1.9.2 veraltet ist ... also benutze CGI::escapeoder ERB :: Util.url_encode .

Für Interessierte gibt es eine lange Diskussion über Ruby-Core, in der auch WEBrick :: HTTPUtils.escape und WEBrick :: HTTPUtils.escape_form erwähnt werden .

Marc-André Lafortune
quelle
11
Nur um die Verwirrung zu vergrößern - Ich habe gerade einen Kommentar auf stackoverflow.com/questions/4967608/… gesehen, in dem jemand erwähnte, dass CGI-Escape '+' anstelle von% 20 für Leerzeichen verwendet und dass dies gegen die 'Spezifikation' verstößt ...
Louis Sayers
18
Eine Alternative ist die Verwendung ERB::Util.url_encode, die ordnungsgemäß %20 für Leerzeichen verwendet wird
Riffraff
1
@Ernest: Siehe: github.com/ruby/ruby/commit/… (Antwort aktualisiert)
Marc-André Lafortune
4
ruby-doc.org/stdlib-2.0.0/libdoc/uri/rdoc/URI/Escape.html . Es gibt das URI.escape-Modul in Ruby 2.0.0. Warum wurde es veraltet?
user938363
1
@ user938363 Wenn Sie dort auf die Show-Quelle klicken, wird diese weiterhin als veraltet markiert.
Zeichnen
229

Was ist der Unterschied zwischen einer Axt und einem Schwert und welches sollte ich verwenden? Nun, es hängt davon ab, was Sie tun müssen.

URI.escapesollte eine Zeichenfolge (URL) in die sogenannte " Prozentcodierung " codieren .

CGI::escapestammt aus der CGI- Spezifikation, die beschreibt, wie Daten zwischen Webserver und Anwendung codiert / decodiert werden sollen.

Angenommen, Sie müssen einem URI in Ihrer App entkommen. Es ist ein spezifischerer Anwendungsfall. Dafür nutzte die Ruby-Community URI.escapejahrelang. Das Problem dabei URI.escapewar, dass die RFC-3896-Spezifikation nicht verarbeitet werden konnte.

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 wurde als veraltet markiert:

Darüber hinaus ist der aktuelle URI.encode einfach gsub. Aber ich denke, es sollte eine URI in Komponenten aufteilen, dann jede Komponente maskieren und sie schließlich verbinden.

Der aktuelle URI.encode wird daher als schädlich und veraltet angesehen. Dies wird entfernt oder das Verhalten drastisch geändert.

Was ist der Ersatz zu diesem Zeitpunkt?

Wie oben erwähnt, ist der aktuelle URI.encode auf Spezifikationsebene falsch. Wir werden also nicht den genauen Ersatz liefern. Der Austausch variiert je nach Anwendungsfall.

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

Leider gibt es in den Dokumenten kein einziges Wort darüber. Die einzige Möglichkeit, dies zu erfahren, besteht darin, die Quelle zu überprüfen oder das Skript mit Warnungen in ausführlicher Ebene ( -wW2) auszuführen (oder Google-Fu zu verwenden).

Einige schlugen vor , CGI::Escapefür Abfrageparameter zu verwenden , da Sie einem gesamten URI nicht entkommen konnten:

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::escapesollte nur für Abfrageparameter verwendet werden, aber die Ergebnisse stimmen wieder mit der Spezifikation überein. Tatsächlich ist der häufigste Anwendungsfall das Entkommen von Formulardaten, z. B. beim Senden einer application/x-www-form-urlencodedPOST-Anforderung.

Ebenfalls erwähnt WEBrick::HTTPUtils.escapewird keine große Verbesserung (wieder ist es nur eine einfache gsub, was IMO sogar eine schlechtere Option ist als 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" 

Das der Spezifikation am nächsten liegende scheint das adressierbare Juwel zu sein:

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"

Beachten Sie, dass Addressable im Gegensatz zu allen vorherigen Optionen nicht maskiert #wird und dies das erwartete Verhalten ist. Sie möchten den #Hash im URI-Pfad behalten, jedoch nicht in der URI-Abfrage.

Das einzige verbleibende Problem ist, dass wir unseren Abfrageparametern nicht richtig entkommen konnten, was uns zu dem Schluss bringt: Wir sollten nicht eine einzige Methode für den gesamten URI verwenden, da es (bisher) keine perfekte Lösung gibt. Wie Sie sehen, &wurde nicht aus "Mein Blog & Ihr Blog" entkommen. Wir müssen für Abfrageparameter eine andere Form der Escape-Funktion verwenden, bei der Benutzer verschiedene Zeichen einfügen können, die in URLs eine besondere Bedeutung haben. Geben Sie die URL-Codierung ein. Die URL-Codierung sollte für jeden "verdächtigen" Abfragewert verwendet werden, ähnlich wie ERB::Util.url_encodefolgt:

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

Es ist cool, aber wir haben bereits Addressable benötigt:

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"

Fazit:

  • Nicht verwenden URI.escapeoder ähnliches
  • Verwenden CGI::escapeSie diese Option, wenn Sie nur eine Formularflucht benötigen
  • Wenn Sie mit URIs arbeiten müssen, verwenden Sie Addressable. Es bietet URL-Codierung, Formularcodierung und normalisiert URLs.
  • Wenn es sich um ein Rails-Projekt handelt, lesen Sie " Wie kann ich eine Zeichenfolge in Rails per URL maskieren? ".
Ernest
quelle
Vielen Dank für die Info. Es hat sicher einige Warnungen vor Hackentests beseitigt. Ein Rechen und eine Hacke sehen unten aus.
Douglas G. Allen
Tolle Erklärung @Ernest, aber das Problem dabei ist, dass es nicht für externe URLs funktioniert, die ich nicht erstellen möchte (und über die ich keine Kontrolle habe). Beispiel: Crawler, die URLs von einer Webseite lesen und dann versuchen, auf diese URLs zuzugreifen (die vor dem Zugriff codiert werden müssen).
amit_saxena
@amit_saxena Wenn Sie es sich leisten können, Addressableeines Ihrer Juwelen zu haben, können Sie zuerst die URL analysieren, z. B. rubydoc.info/gems/addressable/Addressable/URI.heuristic_parse
Ernest
Interessant! Aber auch hier kann ich keinen Hash von Parametern aus der ursprünglichen URL abrufen, die ich dann wie von Ihnen beschrieben codiere. In meinem Fall lautet der Ablauf: Ich erhalte externe URLs von einem Feed -> die ich dann codieren muss -> Übergabe an den http-Client, um Inhalte abzurufen. Wenn ich die externen URLs nicht richtig codiere, schlagen die Ruby-basierten HTTP-Clients mit ungültigen URI-Fehlern fehl.
amit_saxena
@amit_saxena parse Methode gibt Instanz von zurück Addressable:URL, Sie können dann alle Instanzmethoden darauf aufrufen, vielleicht wird eine von ihnen die gewünschten Ergebnisse erhalten: rubydoc.info/gems/addressable/Addressable/URI
Ernest
6

CGI::escapeist gut für das Escape-Text-Segment geeignet, damit sie in URL-Abfrageparametern (Zeichenfolgen nach '?') verwendet werden können. Wenn Sie beispielsweise einen Parameter mit Schrägstrichen in der URL haben möchten, maskieren Sie CGI :: diese Zeichenfolge zuerst und fügen Sie sie dann in die URL ein.

In Rails werden Sie es jedoch wahrscheinlich nicht direkt verwenden. Normalerweise verwenden Sie hash.to_param, die CGI::escapeunter der Haube verwendet werden.


URI::escapeist gut, um einer URL zu entkommen, die nicht richtig maskiert wurde. Beispielsweise geben einige Websites eine falsche / nicht entführte URL in ihrem Ankertag aus. Wenn Ihr Programm diese URLs verwendet, um mehr Ressourcen abzurufen, beschwert sich OpenURI darüber, dass die URLs ungültig sind. Du brauchstURI::escape diese, um eine gültige URL zu erstellen. Es wird also verwendet, um die gesamte URI-Zeichenfolge zu maskieren, damit sie korrekt ist. In meinem Wort macht URI :: unescape eine URL für den Menschen lesbar, und URI :: Escape macht sie für Browser gültig.

Dies ist der Begriff meines Laien und Sie können ihn gerne korrigieren.

lulalala
quelle
1

Der Unterschied ist, dass URI.escape nicht funktioniert ...

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

URI.escape"/en/test?asd=qwe"
=> "/en/test?asd=qwe"
Radu Simionescu
quelle
2
Sie haben den falschen Testfall gewählt. Die / 's ,?' S und = 's sind alle Teil einer gültigen URI und werden daher nicht maskiert. Andere Zeichen, die insbesondere in der Abfragezeichenfolge maskiert werden müssen, sollten sein.
Gerard ONeill
@GerardONeill Ich habe den Testfall genau ausgewählt, um zu zeigen, dass URI.escape nicht funktioniert und unzuverlässig ist. Schlagen Sie vor, dass URI.escape nur die Abfragezeichenfolge maskiert? Wie kann es erkennen, wann ein Parameterwert fertig ist, wenn ich dort ein & codieren möchte? Vielleicht ist es deshalb veraltet?
Radu Simionescu
1
Das ist genau das, was ich sage. Das URI-Escape muss die URL analysieren, die einzelnen Parameter herausfiltern, maskieren und wieder zusammensetzen. Auch das kann chaotisch sein. Aber das tut es nicht - es vermeidet nur, einigen Charakteren zu entkommen, während es dem Rest entgeht, was es unvollständig macht. Es kann für einfache Fälle verwendet werden, insbesondere wenn Sie wissen, dass Ihre Parameter nicht verwirrend sind.
Gerard ONeill
0

CGI.escape dient zum Escapezeichen eines URL-Werts in der Abfragezeichenfolge. Alle Zeichen, die nicht in ALPHA, DIGIT, '_', '-', 'fallen.' und '' Zeichensatz werden maskiert.

Aber das würde eine URL falsch machen, da eine URL '/', ':', '?', '[', '&', '=' Und ';' haben muss. Vielleicht mehr, als ich mir vorstellen kann.

URI.escape lässt diese URL-Zeichen in Ruhe und versucht, die Schlüssel und Werte der Abfragezeichenfolge zu finden, die maskiert werden sollen. Dies kann jedoch nicht wirklich abhängig gemacht werden, da Werte alle Arten von Zeichen enthalten können, die ein leichtes Entkommen verhindern. Grundsätzlich ist es zu spät. Wenn die URL jedoch einfach sein kann (keine '&' s und '=' s usw. in den Werten), kann diese Funktion verwendet werden, um möglicherweise unlesbare oder unzulässige Zeichen zu umgehen.

Im Allgemeinen - verwenden Sie CGI.escape immer für die einzelnen Schlüssel und Werte, bevor Sie sie mit '&' verbinden und nach dem '?' Hinzufügen.

Gerard ONeill
quelle
0

CGI.escape funktionierte nicht mit der OpenProject-API. Es codierte das []: und nicht das +. Ich habe dies zusammen gehackt, was bisher für die OpenProject-API zu funktionieren scheint. Aber ich bin sicher, es fehlen einige .gsub's. Es ist wahrscheinlich fast so schlimm wie URI.escape, aber es gibt Ihnen nicht die veralteten Fehler.

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\"]")

Beide Ausgaben:

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

Brett
quelle