Ruby:强制 open-uri 返回 IPv4 地址

7
在我们的Rails应用中,有一个控制器动作打开一个外部URL,并将其作为JSON返回给前端使用。今天,我收到了以下错误:Errno::EAFNOSUPPORT: Address family not supported by protocol - socket(2)。我们的devops建议如果地址返回IPv6响应和IPv4响应,这将是错误的。我们不支持IPv6,这可能是原因。下面是触发请求的方法:
def medline_response
  open("http://apps.nlm.nih.gov/medlineplus/services/mpconnect_service.cfm?mainSearchCriteria.v.cs=#{codesys}&mainSearchCriteria.v.c=#{code}")
end

实际上,来自该服务器主机的响应是:

$ host apps.nlm.nih.gov
apps.nlm.nih.gov is an alias for apps.wip.nlm.nih.gov.
apps.wip.nlm.nih.gov has address 130.14.16.117
apps.wip.nlm.nih.gov has IPv6 address 2607:f220:41e:1016::117
open-uri文档中没有提到IP版本的内容。是否可以在open方法中传递参数以强制读取IPv4,或者有其他处理方法?

编辑

当我尝试从控制台打开Google时,会出现以下情况:

[18] pry(main)> require 'open-uri'
=> false
[19] pry(main)> open 'http://google.com'   
=> #<File:/var/folders/hq/7_rgkt4565q728y91dtqzs2r2wxb1y/T/open-uri20130913-50258-1af4zhv>

所以看起来IPv6地址在这里不是问题。

编辑2

$ ruby -v
ruby 1.9.3p385 (2013-02-06 revision 39114) [x86_64-darwin11.4.2]

OS X 10.7.5

第三次编辑

这是人人讨厌的错误类型:间歇性错误。当我调用open-uri对象的读取函数时,会出现以下情况。在我们本地和所有3个应用程序服务器上都出现了相同的输出。

[22] pry(main)> open("http://apps.nlm.nih.gov/medlineplus/services/mpconnect_service.cfm?mainSearchCriteria.v.cs=2.16.840.1.113883.6.103&mainSearchCriteria.v.c=238.4").read
=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<feed xml:base=\"http://apps.nlm.nih.gov/medlineplus/services/\" xml:lang=\"en\" xmlns=\"http://www.w3.org/2005/Atom\" xmlns:v3=\"urn:hl7-org:v3\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><title type=\"text\">MedlinePlus Connect</title><subtitle type=\"text\">MedlinePlus Connect results for ICD-9-CM 238.4</subtitle><author><name>U.S. National Library of Medicine</name><uri>http://www.nlm.nih.gov</uri></author><updated type=\"text\">2013-09-13T12:09:48Z</updated><category scheme=\"REDS_MT010001UV\" term=\"MATCHED\"><v3:mainSearchCriteria classCode=\"OBS\" moodCode=\"DEF\" xmlns:v3=\"urn:hl7-org:v3\"><v3:code code=\"KSUBJ\" codeSystem=\"2.16.840.1.113883.5.4\" xmlns:v3=\"urn:hl7-org:v3\"/><v3:value code=\"238.4\" codeSystem=\"2.16.840.1.113883.6.103\" displayName=\"\" xmlns:v3=\"urn:hl7-org:v3\"/></v3:mainSearchCriteria><v3:informationRecipient typeCode=\"IRCP\" xmlns:v3=\"urn:hl7-org:v3\"><v3:patient classCode=\"PAT\" xmlns:v3=\"urn:hl7-org:v3\"/></v3:informationRecipient></category><id></id><entry><title>Bone Marrow Diseases</title><link href=\"http://www.nlm.nih.gov/medlineplus/bonemarrowdiseases.html\" rel=\"alternate\"/><id>tag: nlm.nih.gov, 2013-13-09:/medlineplus/bonemarrowdiseases.html</id><updated>2013-09-13T12:09:48Z</updated><summary type=\"html\">&lt;p&gt;Bone marrow is the spongy tissue inside some of your bones, such as your hip and thigh bones. It contains immature cells, called stem cells. The stem cells can develop into the red blood cells that carry oxygen through your body, the white blood cells that fight infections, and the platelets that help with blood clotting. &lt;/p&gt;&#xd;&#xd;&lt;p&gt;If you have a bone marrow disease, there are problems with the stem cells or how they develop. &lt;a href=\"http://www.nlm.nih.gov/medlineplus/leukemia.html\"&gt;Leukemia&lt;/a&gt; is a cancer in which the bone marrow produces abnormal white blood cells. With &lt;a href=\"http://www.nlm.nih.gov/medlineplus/aplasticanemia.html\"&gt;aplastic anemia&lt;/a&gt;, the bone marrow doesn't make red blood cells. Other diseases, such as &lt;a href=\"http://www.nlm.nih.gov/medlineplus/lymphoma.html\"&gt;lymphoma&lt;/a&gt;, can spread into the bone marrow and affect the production of blood cells.  Other causes of bone marrow disorders include your genetic makeup and environmental factors.&lt;/p&gt; &#xd;&#xd;&lt;p&gt;Symptoms of bone marrow diseases vary. Treatments depend on the disorder and how severe it is. They might involve medicines, blood transfusions or a &lt;a href=\"http://www.nlm.nih.gov/medlineplus/bonemarrowtransplantation.html\"&gt;bone marrow transplant&lt;/a&gt;. &lt;/p&gt;&#xd; &lt;p class=\"NLMrelatedLinks\"&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=\"http://www.nlm.nih.gov/medlineplus/ency/article/003658.htm\"&gt;Bone marrow aspiration&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=\"http://www.nlm.nih.gov/medlineplus/ency/article/003934.htm\"&gt;Bone marrow biopsy&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=\"http://www.nlm.nih.gov/medlineplus/ency/article/003682.htm\"&gt;Bone marrow culture&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=\"http://www.nlm.nih.gov/medlineplus/ency/article/003009.htm\"&gt;Bone marrow transplant&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=\"http://www.nlm.nih.gov/medlineplus/ency/patientinstructions/000010.htm\"&gt;Bone marrow transplant - discharge&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=\"http://www.nlm.nih.gov/medlineplus/ency/article/000589.htm\"&gt;Polycythemia vera&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=\"http://www.nlm.nih.gov/medlineplus/ency/article/000531.htm\"&gt;Primary myelofibrosis&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;</summary></entry></feed>  \n\n"

也就是说,它会将HTML以字符串的形式返回,就像你期望的那样。

如果你用google.com会发生什么?它也有IPv6地址。(当我执行host apps.nlm.nih.gov时,我得到和你一样的结果) - Translunar
1
我不认为问题出在OpenURI或IPv6上,因为如果它们是有问题的配对,我们早就应该听说过了。 OpenURI从处理该URI的主机返回的流中读取,并返回一个文件句柄以便让您在StreamIO或文件上执行操作。尝试在MedLine上进行的“打开”上使用“读取”。另外,请问您使用的是哪个Ruby版本、OpenURI版本和操作系统? - the Tin Man
请查看编辑。我已经添加了那些信息。OpenURI是Ruby核心的一部分,所以它应该是相同的版本,对吗? - nickcoxdotme
不确定这是否重要,但是自从采用ipv6以来,存在一个巨大的问题,因为采用ipv6是由于ipv4已经达到最大容量。因此,有更多的IPv6地址可用(约79 228 162 514 264 337 593 543 950 33个)。当您遇到没有可解析的ipv4的情况时会发生什么? - engineersmnky
你能在主机上禁用IPv6吗?我曾经遇到过类似的问题,SSH默认使用IPv6(主机有IPv6 DNS条目,但没有有效路由),从系统中删除IPv6强制所有内容转换为IPv4,然后一切都重新开始工作了。 - Adam21e
显示剩余5条评论
1个回答

0

看起来你需要更新 Ruby 版本,参见 Ruby Bug 报告

你可以“强制” open-uri 使用 IP,例如:

require 'open-uri'
require 'socket'

url = "google.com"
ip = IPSocket::getaddress(url)

open("http://#{url}") do |f|
  puts "i'm using url #{url} #{f.base_uri}"
end
open("http://#{ip}") do |f|
  puts "i'm using ip #{ip} #{f.base_uri}"
end

如果在该IP上有多个域名,那么打开("http://#{ip}")就没有用了,这在现今是相当普遍的。在这种情况下,你需要使用完整的Net::HTTP而不是简单的open-uri。 - Honza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接