質問

Since the ASP.NET Development server (VS2012) doesn't let us access URL over LAN (!!) and I don't have rights to configure IIS, I am trying to use WEBrick to launch a static website, to get LAN access. I am running Ubuntu with vagrant on Windows.

In the root of my static website, I have created a file app.rb with the following content:

#app.rb

require 'rubygems'
require 'rack'

class App
  def call(env)
    return [200, {"Content-Type" => "text/html"}, "index.html"]
  end
end

Rack::Handler::WEBrick.run(App.new, :Port => 8080)

When I run the server; ruby app.rb, and browse to http://localhost:8080, it gives me this error:

ERROR NoMethodError: undefined method `each' for "index.html":String
    /usr/local/rvm/gems/ruby-1.9.3-p392/gems/rack-1.4.5/lib/rack/handler/webrick.rb:71:in `service'
    /usr/local/rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/webrick/httpserver.rb:138:in `service'
    /usr/local/rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/webrick/httpserver.rb:94:in `run'
    /usr/local/rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/webrick/server.rb:191:in `block in start_thread'

Is there a way to use WEBrick or Thin to run static (HTML / JS) websites?

Edit

I followed Stuart's suggestion and changed the code to:

return [200, {"Content-Type" => "text/html"}, ["index.html"]]

Now, when I am browsing to URL, it renders "index.html" as string instead rendering the file content.

役に立ちましたか?

解決

There is a simple method of serving a folder over HTTP with WEBrick.

And as for Rack, it by itself doesn't deal with serving files. You have to read the file you want to serve over HTTP and give Rack the contents of the file and for that you could try this quick-and-dirty solution:

def call(env)
  contents = File.open("index.html") { |f| f.read }
  return [200, {"Content-Type" => "text/html"}, [contents]]
end

他のヒント

Your response body must be wrapped in an Array:

    return [200, {"Content-Type" => "text/html"}, ["Hello, World!"]]

Note the [ and ] surrounding "Hello, World!". For an explanation of why the Array wrapper is needed, see:

Why is rack response body an array not a string?

And in particular, this section of the Python WSGI specification:

For large files, however, or for specialized uses of HTTP streaming (such as multipart "server push"), an application may need to provide output in smaller blocks (e.g. to avoid loading a large file into memory). It's also sometimes the case that part of a response may be time-consuming to produce, but it would be useful to send ahead the portion of the response that precedes it.

In these cases, applications will usually return an iterator (often a generator-iterator) that produces the output in a block-by-block fashion. These blocks may be broken to coincide with mulitpart boundaries (for "server push"), or just before time-consuming tasks (such as reading another block of an on-disk file).

That spec refers to Python, but the analogue in a Ruby Rack application is wrapping the HTTP response body in an Array (or any Enumerable which responds to the each method).

EDIT: To address the original question's edit, about how to specifically serve an index.html file, you can do that by reading the file and outputting its contents in the Rack response:

    return [200, {"Content-Type" => "text/html"}, [File.read("index.html")]]

EDIT 2: While the above will work for showing index.html only, if you want to serve an entire directory of static resources (JS, CSS, etc.) you can try using the Rack::Static middleware. See its documentation for details, but I think what you're trying to do could be accomplished with this:

require 'rack/static'
use Rack::Static, :urls => {"/" => 'index.html'}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top