【问题标题】:Simple Ruby server setup using Thin as a simple rhtml server (like Webrick)使用 Thin 作为简单 rhtml 服务器的简单 Ruby 服务器设置(如 Webrick)
【发布时间】:2019-07-24 10:42:57
【问题描述】:

我的简单 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 和 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')      
}

【问题讨论】:

    标签: ruby server rack thin webrick


    【解决方案1】:

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


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

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

      一种常见的方法是:

      • 将静态文件放在./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 (security) 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 进行测试)...

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

    编辑

    附: (关于安全性和性能的旁注)

    我会重新考虑模板引擎。

    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)
    

    再次,由于我是碘的作者,我有偏见。到处玩,找到最适合您的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-30
      • 1970-01-01
      • 1970-01-01
      • 2012-02-26
      相关资源
      最近更新 更多