[ruby]Net::HTTPで無限に302 Movedを繰り返すトラブルにあった

まとめ

 res= http.get( url.path )

って書いていると、30x系のリダイレクトでパラメータ付きのURLを指示された時にはまります。url.request_uriを使いましょう。


内容

Google Calendar APIなんかを使ってWEBサービスからデータをとってくる時、net/httpを使うことはよくあるかと思います。

とってきたデータが30x系のリダイレクトであった場合まで考慮に入れたとすると、こんなコードになりますよね?

 max_retry_count = 5

 max_retry_count.times {|retry_count|

  http = Net::HTTP.new(url.host, url.port)

  http.use_ssl = true if (443==url.port)

  http.ca_file = ‘/var/hogehoge/www.google.com.cer’

  http.verify_mode = OpenSSL::SSL::VERIFY_PEER

  http.verify_depth = 5

  res= http.get( url.path )

  

  case res

  when Net::HTTPSuccess

   break

  when Net::HTTPRedirection

   url = URI.parse(res[‘Location’])

   next

  else

   break

  end

 }

 resを使ってあれこれ。

 ところが、これでGoogleカレンダーのデータをとってこようとしたらひどい目に遭います。とりあえずとってくると…

Moved Temporarily

The document has moved https://www.google.com/xxxx?gsessionid=m6Kxxxx

想定の範囲内の302 Moved Temporarilyなので、プログラムはいわれたとおりにリトライして、データをとってきます。

Moved Temporarily

The document has moved https://www.google.com/xxxx?gsessionid=1rJxxxx

え?と思いつつ、プログラムはいわれたとおりにリトライして、データをとってきます。

Moved Temporarily

The document has moved https://www.google.com/xxxx?gsessionid=Cmvxxxx

….たらい回し状態です。いっこうに目的のデータに行き着きません。

やり方が間違っているのかなぁ、それともドキュメントに読み落としがあるかなぁ、とさんざん悩んだ末、やっと原因に気がつきました。

rubyのURIライブラリは、URIを渡すと部品に分解してくれます。host/port/path/query….

そこで、http.get( url.path )を使うと? queryとして指示されている「?gsessionid=Cmvxxxx」が吹っ飛んじゃいますよね。

Googleさんから見ると、

・”xxxx”にクライアントが来たので、”xxxx?gsessionid=….”にリダイレクトを指示しました。

・なぜかクライアントはgsessionidを外して、再び”xxxx”にアクセスしてきました

・仕方がない(というか、別クライアントに見えるので)、”xxxx?gsessionid=….”にリダイレクトを指示しました。

・なぜかクライアントはgsessionidを外して”xxxx”にアクセスしてきたので….

ということになっていたわけです。

….だって みんな“http.get( url.path )” って書くじゃーん!

 res= http.get( url.request_uri )

って書くのがいいみたいです。

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です