为什么Ruby Net :: HTTP.get_response和Net :: HTTP.new(uri.host).request返回不同的东西?

时间:2014-01-22 02:12:48

标签: ruby net-http

这两个请求应该具有相同的结果,但第一个请求返回200(OK),第二个返回404(Not Found)。那是为什么?

require 'net/http'

url = "http://readwrite.com/2013/12/04/google-compute-engine"
uri = URI(url)
Net::HTTP.get_response(uri)
#=> #<Net::HTTPOK 200 OK readbody=true>
Net::HTTP.new(uri.host).request(Net::HTTP::Get.new(url))
#=> #<Net::HTTPNotFound 404 Not Found readbody=true>

只有一些网址才会发生这种情况。我无法弄清楚这种模式。这是另一个例子:http://davidduchemin.com/2014/01/towards-mastery-again/

1 个答案:

答案 0 :(得分:4)

首先,让我们通过用tcpdump查看他们的实际HTTP请求来比较两者,这样我们就可以了解可能发生的事情:

tcpdump -vvASs 0 port 80 and host www.readwrite.com
# Net::HTTP.get_response(uri)

GET /2013/12/04/google-compute-engine HTTP/1.1
Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept: */*
User-Agent: Ruby
Host: readwrite.com
# Net::HTTP.new(uri.host).request(Net::HTTP::Get.new(url))

GET http://readwrite.com/2013/12/04/google-compute-engine HTTP/1.1
Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept: */*
User-Agent: Ruby
Connection: close
Host: readwrite.com

我们可以看到第二个请求错误地请求完整的URL(带有主机名)作为路径。这是因为您将url传递给Net::HTTP::Get.new,这导致Net::HTTP::Get.new(url).path正如我们上面所见:带有主机名的完整网址。而是将URI实例(uri)传递给Net::HTTP::Get.new

Net::HTTP.new(uri.host).request(Net::HTTP::Get.new(uri))
#=> #<Net::HTTPOK 200 OK readbody=true>

现在它的tcpdump实际上与第一个相同:

GET /2013/12/04/google-compute-engine HTTP/1.1
Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept: */*
User-Agent: Ruby
Host: readwrite.com
Connection: close