Gangmax Blog

Hello Rack!

今天看到这篇文章,我就按照上面的指示尝试运行rack

第一次尝试:

1
2
3
4
5
irb
1.9.2p318 :001 > require 'rack'
=> true
1.9.2p318 :002 > Rack::Handler::Mongrel.run proc {|env| [200, {"Content-Type" => "text/html"}, "Hello Rack!"]}, :Port => 9292

打开浏览器,输入””http://localhost:9292“”,没有输出,控制台有以下错误:

1
2
3
4
5
6
7
LoadError: no such file to load -- mongrel
from /home/user/.rvm/rubies/ruby-1.9.2-p318/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /home/user/.rvm/rubies/ruby-1.9.2-p318/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /home/user/.rvm/gems/ruby-1.9.2-p318/gems/rack-1.4.1/lib/rack/handler/mongrel.rb:1:in `<top (required)>'
from (irb):2
from /home/user/.rvm/rubies/ruby-1.9.2-p318/bin/irb:16:in `<main>'
1.9.2p318 :003 > exit

这是提示我本地没有安装mongrel gem,安装之:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
gem install mongrel
Fetching: gem_plugin-0.2.3.gem (100%)
Fetching: daemons-1.1.8.gem (100%)
Fetching: fastthread-1.0.7.gem (100%)
Building native extensions. This could take a while...
Fetching: cgi_mu:ltipart_eof_fix-2.5.0.gem (100%)
Fetching: mongrel-1.1.5.gem (100%)
Building native extensions. This could take a while...
ERROR: Error installing mongrel:
ERROR: Failed to build gem native extension.

/home/user/.rvm/rubies/ruby-1.9.2-p318/bin/ruby extconf.rb
checking for main() in -lc... yes
creating Makefile

make
gcc -I. -I/home/user/.rvm/rubies/ruby-1.9.2-p318/include/ruby-1.9.1/i686-linux -I/home/user/.rvm/rubies/ruby-1.9.2-p318/include/ruby-1.9.1/ruby/backward -I/home/user/.rvm/rubies/ruby-1.9.2-p318/include/ruby-1.9.1 -I. -I/home/user/.rvm/usr/include -D_FILE_OFFSET_BITS=64 -fPIC -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -fPIC -o http11_parser.o -c http11_parser.c
http11_parser.rl: In function ‘http_parser_execute’:
http11_parser.rl:105: warning: comparison between signed and unsigned integer expressions
gcc -I. -I/home/user/.rvm/rubies/ruby-1.9.2-p318/include/ruby-1.9.1/i686-linux -I/home/user/.rvm/rubies/ruby-1.9.2-p318/include/ruby-1.9.1/ruby/backward -I/home/user/.rvm/rubies/ruby-1.9.2-p318/include/ruby-1.9.1 -I. -I/home/user/.rvm/usr/include -D_FILE_OFFSET_BITS=64 -fPIC -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -fPIC -o http11.o -c http11.c
http11.c: In function ‘http_field’:
http11.c:70: warning: format not a string literal and no format arguments
http11.c:71: warning: format not a string literal and no format arguments
http11.c:77: error: ‘struct RString’ has no member named ‘ptr’
http11.c:77: error: ‘struct RString’ has no member named ‘len’
http11.c: In function ‘request_uri’:
http11.c:102: warning: format not a string literal and no format arguments
http11.c: In function ‘fragment’:
http11.c:113: warning: format not a string literal and no format arguments
http11.c: In function ‘request_path’:
http11.c:124: warning: format not a string literal and no format arguments
http11.c: In function ‘query_string’:
http11.c:135: warning: format not a string literal and no format arguments
http11.c: In function ‘header_done’:
http11.c:172: error: ‘struct RString’ has no member named ‘ptr’
http11.c:172: error: ‘struct RString’ has no member named ‘ptr’
http11.c:172: error: ‘struct RString’ has no member named ‘ptr’
http11.c:174: error: ‘struct RString’ has no member named ‘ptr’
http11.c:176: error: ‘struct RString’ has no member named ‘ptr’
http11.c:177: error: ‘struct RString’ has no member named ‘len’
http11.c: In function ‘HttpParser_execute’:
http11.c:298: error: ‘struct RString’ has no member named ‘ptr’
http11.c:299: error: ‘struct RString’ has no member named ‘len’
http11.c:307: warning: format not a string literal and no format arguments
make: *** [http11.o] 错误 1


Gem files will remain installed in /home/user/.rvm/gems/ruby-1.9.2-p318/gems/mongrel-1.1.5 for inspection.
Results logged to /home/user/.rvm/gems/ruby-1.9.2-p318/gems/mongrel-1.1.5/ext/http11/gem_make.out

安装失败。google原因,这里有答案:因为我使用的是Ruby-1.9.2,默认的”mongrel-1.1.5”不能使用,需要安装”mongrel-1.2.0.pre2”版本:

1
gem install mongrel --pre

此时运行”gem list”,可以看到mongrel已经被安装成功。

1
mongrel (1.2.0.pre2)

再次尝试运行:

1
2
3
4
irb
1.9.2p318 :001 > require 'rack'
=> true
1.9.2p318 :002 > Rack::Handler::Mongrel.run proc {|env| [200, {"Content-Type" => "text/html"}, "Hello Rack!"]}, :Port => 9292

此时使用浏览器浏览”http://localhost:9292“,控制台依然有错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2012-03-24 12:18:56 +0800: Read error: #<NoMethodError: undefined method `each' for "Hello Rack!":String>
/home/user/.rvm/gems/ruby-1.9.2-p318/gems/rack-1.4.1/lib/rack/handler/mongrel.rb:90:in `process'
/home/user/.rvm/gems/ruby-1.9.2-p318/gems/mongrel-1.2.0.pre2/lib/mongrel.rb:165:in `block in process_client'
/home/user/.rvm/gems/ruby-1.9.2-p318/gems/mongrel-1.2.0.pre2/lib/mongrel.rb:164:in `each'
/home/user/.rvm/gems/ruby-1.9.2-p318/gems/mongrel-1.2.0.pre2/lib/mongrel.rb:164:in `process_client'
/home/user/.rvm/gems/ruby-1.9.2-p318/gems/mongrel-1.2.0.pre2/lib/mongrel.rb:291:in `block (2 levels) in run'
^CIRB::Abort: abort then interrupt!!
from /home/user/.rvm/gems/ruby-1.9.2-p318/gems/rack-1.4.1/lib/rack/handler/mongrel.rb:38:in `call'
from /home/user/.rvm/gems/ruby-1.9.2-p318/gems/rack-1.4.1/lib/rack/handler/mongrel.rb:38:in `join'
from /home/user/.rvm/gems/ruby-1.9.2-p318/gems/rack-1.4.1/lib/rack/handler/mongrel.rb:38:in `run'
from (irb):8
from /home/user/.rvm/rubies/ruby-1.9.2-p318/bin/irb:16:in `<main>'
1.9.2p318 :009 > Rack::Handler::Mongrel.run HelloWorld.new, :Port =>9292
Errno::EADDRINUSE: Address already in use - bind(2)
from /home/user/.rvm/gems/ruby-1.9.2-p318/gems/mongrel-1.2.0.pre2/lib/mongrel/tcphack.rb:12:in `initialize'
from /home/user/.rvm/gems/ruby-1.9.2-p318/gems/mongrel-1.2.0.pre2/lib/mongrel/tcphack.rb:12:in `initialize_with_backlog'
from /home/user/.rvm/gems/ruby-1.9.2-p318/gems/mongrel-1.2.0.pre2/lib/mongrel.rb:99:in `new'
from /home/user/.rvm/gems/ruby-1.9.2-p318/gems/mongrel-1.2.0.pre2/lib/mongrel.rb:99:in `initialize'
from /home/user/.rvm/gems/ruby-1.9.2-p318/gems/rack-1.4.1/lib/rack/handler/mongrel.rb:10:in `new'
from /home/user/.rvm/gems/ruby-1.9.2-p318/gems/rack-1.4.1/lib/rack/handler/mongrel.rb:10:in `run'
from (irb):9
from /home/user/.rvm/rubies/ruby-1.9.2-p318/bin/irb:16:in `<main>'

Google该错误,这里有解释:原因在于”Ruby-1.9”不再支持”String”的”each”方法,而”rack-1.4.1”仍然使用了该方法。解决办法就是修改该用法,打开本地的”rack-1.4.1”的对应文件”~/.rvm/gems/ruby-1.9.2-p318/gems/rack-1.4.1/lib/rack/handler/mongrel.rb”文件,修改第90行并保存:

From:

1
body.each { |part|

To:

1
body.each_line { |part|

第三次尝试:

1
2
3
4
gang@hp560-ubuntu:~$ irb
1.9.2p318 :001 > require 'rack'
=> true
1.9.2p318 :002 > Rack::Handler::Mongrel.run proc {|env| [200, {"Content-Type" => "text/html"}, "Hello Rack!"]}, :Port => 9292

在浏览器中输入”http://localhost:9292“,这次,终于可以看到”Hello Rack!”了。

感想:

  1. 动态类型语言无法由编译器在编译期找到”类型不匹配”、”方法找不到”等错误(这些错误是静态类型语言编译器可以帮你发现的,比如Java),这些问题只有在Runtime运行期才能被发现,这是动态类型语言强大灵活性所必须付出的代价;

  2. 当你发现解释性语言的错误时,修改很简单。直接修改,因为不需要编译过程。

Comments