如何让 Sinatra 与 HTTPClient 一起工作?

问题描述:

我正在尝试创建一个外观 API,它通过 Sinatra 接收请求,然后在后端的 Github API 上启动 HTTP 请求.

I'm trying to create a facade API that receives requests via Sinatra then launches HTTP requests on Github API in the backend.

在我的hello world"脚本中:

In my "hello world" script I have:

#!/usr/bin/ruby

require 'httpclient'
require 'sinatra'

get '/foo' do
    "hello world"
end

但是,它遇到了如下错误:

However, it runs into errors like:

$ ./api.rb 
/usr/local/share/gems/gems/sinatra-1.4.3/lib/sinatra/base.rb:1408:in `run!': undefined method `run' for HTTP:Module (NoMethodError)
from /usr/local/share/gems/gems/sinatra-1.4.3/lib/sinatra/main.rb:25:in `block in <module:Sinatra>'

我不明白为什么会发生这种情况.如果我注释掉 require 'httpclient' 行,它就可以正常工作:

I don't understand why this happens. If I comment out the require 'httpclient' line, it works just fine:

#!/usr/bin/ruby

#require 'httpclient'
require 'sinatra'

get '/foo' do
  "hello world"
end

$ ./api.rb 
[2013-06-26 21:43:12] INFO  WEBrick 1.3.1
[2013-06-26 21:43:12] INFO  ruby 1.9.3 (2013-05-15) [x86_64-linux]
[2013-06-26 21:43:12] WARN  TCPServer Error: Cannot assign requested address - bind(2)
== Sinatra/1.4.3 has taken the stage on 4567 for development with backup from WEBrick
[2013-06-26 21:43:12] INFO  WEBrick::HTTPServer#start: pid=31272 port=4567

我的猜测是 Sinatra 本身正在使用 HTTPClient,并且正在发生某种命名空间冲突.有没有办法同时使用 HTTPClient 和 Sinatra?

My guess is that Sinatra is using HTTPClient by itself and some kind of namespace collision is happening. Is there a way to use HTTPClient and Sinatra at the same time?

好的,这里是请求的信息:

OK here is the requested info:

$ gem list sinatra httpclient

*** LOCAL GEMS ***

sinatra (1.4.3)

$ gem out sinatra httpclient
bigdecimal (1.1.0 < 1.2.0)
io-console (0.3 < 0.4.2)
json (1.6.8 < 1.8.0)
rdoc (3.12 < 4.0.1)

我通过这种方式找出了 httpclient 版本:

I figured out httpclient version this way:

$ locate httpclient.rb
/usr/local/share/gems/gems/httpclient-2.3.3/lib/httpclient.rb
/usr/local/share/gems/gems/httpclient-2.3.3/test/test_httpclient.rb

我的操作系统是 Fedora 17,但不确定是否重要.

My OS is Fedora 17, though not sure if it matters.

我找到了原因.HTTPClient 定义了一个名为 HTTP 的模块.默认情况下,Sinatra 会按照命名空间名称 HTTPWEBrick 的顺序查找 Rack 处理程序.

I found the reason. HTTPClient defines a module named HTTP. By default Sinatra looks for Rack handlers with namespace names HTTP and WEBrick, in that order.

自从定义了 HTTP 命名空间后,Sinatra 实际上认为它是一个 Rack 处理程序.我认为这是 Sinatra 中的一个错误.在使用之前,它应该检查处理程序是否响应 run.

Since the HTTP namespace has been defined Sinatra actually thinks it's a Rack handler. I think this is a bug in Sinatra. It should check if the handler responds to run before using it.

无论如何修复是使用 Thin,或者如果您想使用 WEBrick 然后通过执行以下操作明确告诉 Sinatra 跳过自动机架检测:

Anyway the fix is to use Thin, or if you want to use WEBrick then explicitly tell Sinatra to skip the automatic Rack detection by doing:

set :server, 'webrick'

这将防止 Sinatra 认为 HTTPClient HTTP 模块是 Rack 处理程序.

That will prevent Sinatra from thinking the HTTPClient HTTP module is Rack handler.