URI.escapeとCGI.escapeの違いは何ですか?


147

違いは何だURI.escapeCGI.escape、もう1つは、私が使用する必要がありますか?

回答:


124

いくつかの小さな違いがありましたが、重要な点は、Ruby 1.9.2 URI.escapeでは非推奨になっていることです。そのため、CGI::escapeまたはERB :: Util.url_encodeを使用してください

長い議論があるルビー・コア上にも言及し、それらの興味のためにWEBrickに:: HTTPUtils.escapeWEBrickに:: HTTPUtils.escape_formが


11
混乱を増すために-私はちょうどstackoverflow.com/questions/4967608/…でコメントを見たところ、cgiエスケープはスペースに%20の代わりに「+」を使用し、それは「仕様」に反すると述べた...
ルイ・セイヤーズ

18
代替が使用されERB::Util.url_encode、適切に使用している%20 スペースのために
riffraff


4
ruby-doc.org/stdlib-2.0.0/libdoc/uri/rdoc/URI/Escape.html。ruby 2.0.0にはURI.escapeモジュールがあります。なぜ廃止されたのですか?
user938363

1
@ user938363でそこのソース表示をクリックすると、非推奨としてマークされたままになります。
2014

229

斧と剣の違いは何ですか?どちらを使うべきですか?まあそれあなたが何をする必要があるかに依存します。

URI.escape文字列(URL)をいわゆる「パーセントエンコーディング」にエンコードすることになっていた。

CGI::escapeは、CGI仕様に由来しています。CGI仕様では、Webサーバーとアプリケーションの間でデータをエンコード/デコードする方法について説明しています。

ここで、アプリのURIをエスケープする必要があるとしましょう。より具体的なユースケースです。そのため、RubyコミュニティURI.escapeは長年使用されていました。の問題URI.escapeは、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 廃止としてマークされました:

さらに、現在のURI.encodeは単純なgsubです。しかし、URIをコンポーネントに分割し、各コンポーネントをエスケープして、最後にそれらを結合する必要があると思います。

そのため、現在のURI.encodeは有害であると見なされ、非推奨になっています。これは削除されるか、動作が大幅に変更されます。

現時点での交換は何ですか?

上で述べたように、現在のURI.encodeは仕様レベルでは間違っています。そのため、正確な代替品は提供しません。交換は、そのユースケースによって異なります。

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

残念ながら、ドキュメントにはそれについて一言もありません。それを知る唯一の方法は、ソースを確認するか、詳細レベル(-wW2)で警告付きでスクリプトを実行する(またはgoogle-fuを使用する)ことです。

いくつかは、提案を使用してCGI::Escape、あなたが全体の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::escapeクエリパラメータのみに使用する必要がありますが、結果は仕様に反します。実際、最も一般的な使用例は、application/x-www-form-urlencodedPOSTリクエストの送信中など、フォームデータのエスケープです。

また、WEBrick::HTTPUtils.escapeあまり改善されていません(gsubこれも単純な、つまりIMOであり、よりも悪いオプションです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" 

仕様に最も近いのは、アドレス指定可能な gemです。

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"

以前のすべてのオプションとは異なり、Addressableはエスケープしないこと#に注意してください。これは予想される動作です。#ハッシュをURIパスに保持し、URIクエリには保持しない場合。

残っている唯一の問題は、クエリパラメータを適切にエスケープしなかったということです。これにより、URI全体に対して単一のメソッドを使用すべきではありません。これまでのところ、完全な解決策はないからです。あなたが見るよう&に、「私のブログとあなたのブログ」から逃れられませんでした。クエリパラメータには異なる形式のエスケープを使用する必要があります。ユーザーはURLで特別な意味を持つさまざまな文字を使用できます。URLエンコードを入力します。URLエンコードは、「疑わしい」クエリ値ごとに使用する必要があります。ERB::Util.url_encode

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

すばらしいですが、Addressableは既に必要です。

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"

結論:

  • 使ってはいけません URI.escapeまたは類似したもの
  • 使用する CGI::escapeフォームエスケープのみが必要な場合にます
  • URIを使用する必要がある場合は、Addressableを使用します。これにより、URLエンコード、フォームエンコード、およびURLの正規化が提供されます。
  • Railsプロジェクトの場合は、「Railsで文字列をURLエスケープするにはどうすればよいですか」を確認してください

情報をありがとうございました。それは確かにいくつかの鍬のテスト警告を取り除きました。熊手と鍬が下に見えます。
ダグラスG.アレン

@Ernestの素晴らしい説明ですが、これに関する問題は、私が作成しようとしていない(そして制御できない)外部URLでは機能しないことです。たとえば、ウェブページからURLを読み取り、それらのURLにアクセスしようとするクローラー(アクセスする前にエンコードする必要があります)。
amit_saxena 2014年

@amit_saxena Addressablegemの1つとして使用する余裕がある場合は、最初にURLを解析できます。firubydoc.info/gems/addressable/Addressable/URI.heuristic_parse
Ernest

面白い!しかし、これも、元のURLからパラメーターのハッシュを取得することはできません。私の場合のフローは、いくつかのフィードから外部URLを取得します->エンコードする必要があります-> httpクライアントに渡してコンテンツを取得します。外部URLを適切にエンコードしないと、RubyベースのHTTPクライアントが無効なURIエラーで失敗します。
amit_saxena 2014年

@amit_saxena解析メソッドはのインスタンスを返します。Addressable:URLその後、そのインスタンスのすべてのメソッドを呼び出すことができます。おそらくそのうちの1つが目的の結果を得るでしょう:rubydoc.info/gems/addressable/Addressable/URI
Ernest


6

CGI::escapeテキストセグメントのエスケープに適しているため、URLクエリパラメータ( '?'の後の文字列)で使用できます。たとえば、URLにスラッシュ文字を含むパラメーターが必要な場合は、最初にその文字列をCGI :: escapeしてから、URLに挿入します。

ただし、Railsではおそらく直接使用することはないでしょう。通常、内部でhash.to_param使用するを使用CGI::escapeします。


URI::escape正しくエスケープされなかったURLをエスケープするのに適しています。たとえば、一部のWebサイトは、アンカータグに間違った/エスケープされていないURLを出力します。プログラムがこれらのURLを使用してより多くのリソースをフェッチする場合、OpenURIはURLが無効であると文句を言います。必要があるURI::escape有効なURLにするためには、これらを使用するます。したがって、URIストリング全体をエスケープして適切にするために使用されます。私の言葉では、URI :: unescapeはURLを人間が読めるようにし、URI :: escapeはそれをブラウザに有効にします。

これらは私の素人の用語であり、自由に修正してください。


1

違いは、URI.escapeが機能しないことです...

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

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

2
間違ったテストケースを選択しました。/、?、=はすべて有効なURIの一部であり、エスケープされません。特にクエリ文字列でエスケープする必要がある他の文字はエスケープする必要があります。
Gerard ONeill、

@GerardONeill私はURI.escapeが機能しておらず、信頼性がないことを示すために、テストケースを正確に選択しました。URI.escapeがクエリ文字列のみをエスケープしていることを示唆していますか?&をエンコードしたい場合、パラメーター値がいつ終了したかをどのように判断できますか?おそらくそれが時代遅れの理由ですか?
Radu Simionescu、

1
それがまさに私が言っていることです。URIエスケープでは、URLを解析し、個々のパラメーターと考えられるものを分離し、エスケープして、元に戻す必要があります。それでも面倒なことがある。しかし、それはそれをしません-それは、残りをエスケープする間、いくつかの文字をエスケープすることを避けます、それはそれを不完全にします。特にパラメーターが混乱しないことがわかっている場合は、単純なケースで使用できます。
Gerard ONeill

0

CGI.escapeは、クエリ文字列のURL値をエスケープするためのものです。ALPHA、DIGIT、「_」、「-」、「。」に該当しないすべての文字。および ''文字セットはエスケープされます。

ただし、URLには「/」、「:」、「?」、「[」、「&」、「=」、および「;」が必要なため、URLは正しくありません。おそらく、頭のてっぺんからは考えられないことでしょう。

URI.escapeはこれらのURL文字をそのままにし、エスケープするクエリ文字列のキーと値を見つけようとします。ただし、値はすべての種類の文字を含むことができるため、簡単にエスケープできないため、これに依存することはできません。基本的に、手遅れです。ただし、URLが単純である(値に「&」や「=」などが含まれていない)と依存できる場合、この関数を使用して、読み取り不能または不正な文字をエスケープすることができます。

一般に、「&」で結合して「?」の後に追加する前に、常に個々のキーと値にCGI.escapeを使用します。


0

CGI.escapeはOpenProject APIでは機能しませんでした。+ではなく、[] 、:をエンコードしました。私はこれを一緒にハッキングしましたが、これは今のところOpenProjectのAPIで機能しているようです。しかし、いくつかの.gsubが欠落していると確信しています。URI.escapeとほぼ同じくらい悪い可能性がありますが、廃止されたエラーは表示されません。

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

両方の出力:

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.