使用Thin作为简单的rhtml服务器(例如Webrick)进行简单的Ruby服务器设置

时间:2019-03-02 17:03:54

标签: ruby server rack thin webrick

我简单的Webrick服务器提供了静态html和rhtml嵌入式ruby文件。我如何使用Thin之类的多线程或多进程Ruby服务器实现相同的目标?

Webrick设置:

#!/usr/bin/ruby
# simple_servlet_server.rb
require 'webrick'
include WEBrick
s = HTTPServer.new(:Port => 8000)

# Add a mime type for *.rhtml files
HTTPUtils::DefaultMimeTypes.store('rhtml', 'text/html')

s.mount('/', HTTPServlet::FileHandler, './public_html')

['TERM', 'INT'].each do |signal|
 trap(signal){ s.shutdown }
end

s.start

我已经安装了Thin and Rack,我的config.ru读取HTML但不会呈现rhtml文档?:

  use Rack::Static,
  :urls => ["/images", "/js", "/css"],
  :root => "public"

run lambda { |env|
  [
    200,
    {
      'Content-Type'  => 'text/html',
      'Cache-Control' => 'public, max-age=86400'
    },
    File.open('./public_html', File::RDONLY)
  ]

  HTTPUtils::DefaultMimeTypes.store('rhtml', 'text/html')      
}

1 个答案:

答案 0 :(得分:0)

TL; DR; -动态红宝石内容(即.rhtml文件)需要由模板引擎呈现; WebRick使用的内置引擎是R​​uby的ERB引擎;在发送Rack响应之前渲染动态文件。


  1. 我建议您将静态文件与动态文件分开。

    这将允许您使用反向代理(即nginx)或启用了静态文件的Ruby服务器(即iodine)来优化静态文件服务。

    一种常见的方法是:

    • 将静态文件放在./public下。

    • 将动态文件放在./app/views下。

  2. 您的Rack应用程序将需要使用适当的模板引擎处理器来处理动态文件。

    对于您的.rhtml文件,我会假定,这将是内置的ERB模板引擎(关于here的一篇不错的文章)。

假设您已按照上述放置了动态文件和静态文件,则可能会从一个config.ru文件开始,如下所示:

require 'erb'
require 'pathname'

ROOT ||= Pathname.new(File.dirname(__FILE__)).expand_path

module APP
  VIEWS = ROOT.join('app', 'views')
  def self.call(env)
    # prevent folder trasversal (scurity) and extract file name
    return [403, {}, ["Not Allowed!"]] if env['PATH_INFO'].index("..") || env['PATH_INFO'].index("//")
    filename = VIEWS.join(env['PATH_INFO'][1..-1])
    # make sure file exists
    return [404, {}, ["Not Found"]] unless File.exists?(filename)
    # process dynamic content
    template = IO.binread filename
    data = ERB.new(template).result(binding)
    return [200, {}, [data]]
  end
end

run APP

接下来,您可以使用iodine运行应用程序,该应用程序将处理静态文件服务部分(在此示例中,每个内核一个线程工作线程):

iodine -w -1 -t 1 -www public

当然,您可以使用Rack::Static中间件,但事实证明它要慢得多(自己进行基准测试或针对Thin进行测试)...

...我是碘的作者,所以我可能会有偏见。

编辑

P.S。 (有关安全性和性能的旁注)

我会重新考虑模板引擎。

ERB快速有效,但是它也允许在模板内执行代码。

这可能会导致项目维护困难,因为代码会泄漏到模板中,从而使代码的可读性和维护难度降低。

我会考虑切换到Mustache模板,以防止代码在模板中运行。

更改模板引擎也可以提高性能。考虑使用iodine flavored mustache templates(提供积极的HTML转义)的以下基准测试:

require 'iodine'
require 'erb'
require 'benchmark'

module Base
  ERB_ENG = ERB.new("<%= data %> <%= Time.now %>")
  MUS_ENG = Iodine::Mustache.new(nil, "{{ data }} {{ date }}")
  def self.render_erb(data)
    ERB_ENG.result(binding)
  end
  def self.render_mus(data)
    h = {data: data, date: Time.now.to_s }
    MUS_ENG.render(h)
  end
end

puts "#{Base.render_mus("hello")} == #{Base.render_erb("hello")} : #{(Base.render_mus("hello") == Base.render_erb("hello"))}"

TIMES = 100_000
Benchmark.bm do |bm|
  bm.report("Ruby ERB") { TIMES.times { Base.render_erb("hello") } }
  bm.report("Iodine  ") { TIMES.times { Base.render_mus("hello") } }
end

在我的机器上,结果是(越低越好):

            user     system      total        real
Ruby ERB  1.701363   0.006301   1.707664 (  1.709132)
Iodine    0.256918   0.000750   0.257668 (  0.258190)

再说一次,因为我是碘的作者,所以我有偏见。玩转,找到最适合您的东西。