是否可以使用Crystal创建一个简单的web服务器,为HTML、CSS和JS页面提供服务?
我当前的代码是:
require "http/server"
Port = 8080
Mime = "text/html"
server = HTTP::Server.new([HTTP::ErrorHandler.new, HTTP::LogHandler.new]) do |context|
req = context.request
if req.method == "GET"
filename = File.join(Dir.current, "index.html")
context.response.content_type = Mime
context.response.content_length = File.size(filename)
File.open(filename) { |file| IO.copy(file, context.response) }
next
end
context.response.content_type = Mime
end
puts "e[1;33mStarted Listening on Port #{Port}e[0m"
server.listen(Port)
当我运行compile并运行程序时,它会初始化服务器,但有几个问题:
- 在Firefox浏览器的"Inspect Element"控制台中,我看到:
The stylesheet http://127.0.0.1:8080/styling.css was not loaded because its MIME type, "text/html", is not "text/css". 127.0.0.1:8080
The script from “http://127.0.0.1:8080/javascript.js” was loaded even though its MIME type (“text/html”) is not a valid JavaScript MIME type. 127.0.0.1:8080
SyntaxError: expected expression, got '<' javascript.js:1
服务器只显示index.html
的内容。
当我使用WEBrick运行或直接将index.HTML加载到浏览器时,HTML、CSS和JS代码是完全有效的。
- 无法从本地网络上的任何其他设备访问我的服务器
您可能需要使用HTTP::StaticFileHandler
。它提供来自本地目录的文件。
- 在处理程序中,无论请求是什么,您总是读取文件
index.html
。这是不起作用的 HTTP::Server#listen
在127.0.0.1
上侦听,因此它只能从localhost上使用。为了能够从网络访问,您需要侦听网络上可用的地址。例如,server.listen("0.0.0.0", Port)
将监听所有接口
非常感谢@Johannes Müller解决了我的问题。在这里,我正在分享我想要的代码。
代码:
#!/usr/bin/env crystal
require "http/server"
# Get the Address
ADDR = (ARGV.find { |x| x.split(".").size == 4 } || "0.0.0.0").tap { |x| ARGV.delete(x) }
.split(".").map { |x| x.to_i { 0 } }.join(".")
# Get the Port
PORT = ARGV.find { |x| x.to_i { 0 } > 0 }.tap { |x| ARGV.delete(x) }.to_s.to_i { 8080 }
# Get the path
d = Dir.current
dir = ARGV[0] rescue d
path = Dir.exists?(dir) ? dir : Dir.exists?(File.join(d, dir)) ? File.join(d, dir) : d
listing = !!Dir.children(path).find { |x| x == "index.html" }
actual_path = listing ? File.join(path, "index.html") : path
server = HTTP::Server.new([
HTTP::ErrorHandler.new,
HTTP::LogHandler.new,
HTTP::StaticFileHandler.new(path, directory_listing: !listing)
]) do |context|
context.response.content_type = "text/html"
File.open(actual_path) { |file| IO.copy(file, context.response) }
end
puts "e[1;33m:: Starting Sharing e[38;5;75m#{actual_path}e[1;31m on e[38;5;226mhttp://#{ADDR}:#{PORT}e[0m"
server.listen(::ADDR, ::PORT)
这段代码在提供的路径(默认Dir.current(中查找一个"index.html"文件,如果找到,它会将index.html文件共享到提供的IP地址(默认0.0.0.0(和端口(默认8080(,否则它只共享当前目录内容。
正在运行:
crystal code.cr /tmp/ 5020 127.0.0.1
选项可以被打乱。例如:
crystal code.cr 5020 /tmp/ 127.0.0.1
或
crystal code.cr 5020 127.0.0.1 /tmp
这将启动服务器并共享/tmp目录。如果在/tmp/目录中找到index.html文件,则请求的浏览器将显示index.html内容,或者它的工作方式类似于FTP(尽管不是(。
编译和运行:
crystal build code.cr
./code [options]
如果您不想深入研究本机代码&想要一个简单的解决方案-您应该使用任何提供文件服务器的框架。
您可以为此使用Shivneri框架。Shivneri内置易于配置的文件服务器-
Shivneri.folders = [{
path: "/",
folder: File.join(Dir.current, "assets"),
}]
您可以添加任意数量的文件夹。每个文件夹都将使用提供的路径进行映射。
欲了解更多信息,请阅读文档-https://shivneriforcrystal.com/tutorial/file-server/