在Scala中启动网络服务器
下面是用Python实现的内容:
$ apt-get install python
$ easy_install Flask
$ cat > hello.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
$ python hello.py
只用4个命令和7行代码就能让一个网页服务器运行,真是太厉害了。
那用Scala怎么做呢?
8 个回答
9
我知道Max已经提到过这个,但我忍不住想说一下Scalatra的六行“你好,世界”代码:
import org.scalatra._
class ScalatraExample extends ScalatraServlet {
get("/") {
<h1>Hello, world!</h1>
}
}
总之,可以看看可用的Scala网页框架。
编辑
有些讨论是关于准备好工具有多简单,特别是关于Lift框架的。所以,这里有一个在Ubuntu上的操作过程。我大部分时间都在搞清楚Sun的Java在包管理器里去哪了。总之,一旦Java安装好了,接下来就是这样进行的,省略了所有信息,这样大家可以看到我实际输入的内容:
dcs@dcs-desktop:~$ wget -q -O bin/sbt-launch.jar http://simple-build-tool.googlecode.com/files/sbt-launch-0.7.4.jar
dcs@dcs-desktop:~$ echo 'java -Xmx512M -jar `dirname $0`/sbt-launch.jar "$@"' > bin/sbt
dcs@dcs-desktop:~$ chmod u+x bin/sbt
dcs@dcs-desktop:~$ mkdir app
dcs@dcs-desktop:~$ cd app
dcs@dcs-desktop:~/app$ sbt
Project does not exist, create new project? (y/N/s) s
> *lifty is org.lifty lifty 1.4
> lifty create project-blank sample 2.1
> reload
> update
> jetty-run
好了,网页服务器已经在运行了。当然,你得提前了解SBT和Lifty,才能知道要用它们来运行Scala的Lift程序。不过,另一方面,我之前从没听说过Flask,所以我肯定会花更多时间去弄清楚如何在Python中启动一个网页服务器应用,而不是在Lift中。
我第一次尝试的时候也没有成功——我试着用Scala 2.8.1(上面的代码使用的是默认的2.7.7版本,虽然2.8.0也可以),结果发现那个版本的Scala还没有Lift的版本。另一方面,我已经安装了lifty,只是为了展示安装它的命令而卸载了它。
我希望能有一个适用于Debian/Ubuntu的SBT包——毕竟它只是一个小的shell脚本和一个jar文件,能处理下载Scala、Lift等的工作,而且可以根据你需要的版本来下载。
这和Python和Ruby的模型不同,那些语言自带的包管理器能处理大部分事情。
9
你可以看看这个网站 Unfiltered,可能会对你有帮助。
11
这段话提到的是使用JDK6中自带的HttpServer类。欢迎大家提出改进意见,因为我对Scala还不太熟悉。
package org.test.simplehttpserver
import java.net.InetSocketAddress
import com.sun.net.httpserver.{HttpExchange, HttpHandler, HttpServer}
import collection.mutable.HashMap
abstract class SimpleHttpServerBase(val socketAddress: String = "127.0.0.1",
val port: Int = 8080,
val backlog: Int = 0) extends HttpHandler {
private val address = new InetSocketAddress(socketAddress, port)
private val server = HttpServer.create(address, backlog)
server.createContext("/", this)
def redirect(url: String) =
<html>
<head>
<meta http-equiv="Refresh" content={"0," + url}/>
</head>
<body>
You are being redirected to:
<a href={url}>
{url}
</a>
</body>
</html>
def respond(exchange: HttpExchange, code: Int = 200, body: String = "") {
val bytes = body.getBytes
exchange.sendResponseHeaders(code, bytes.size)
exchange.getResponseBody.write(bytes)
exchange.getResponseBody.write("\r\n\r\n".getBytes)
exchange.getResponseBody.close()
exchange.close()
}
def start() = server.start()
def stop(delay: Int = 1) = server.stop(delay)
}
abstract class SimpleHttpServer extends SimpleHttpServerBase {
private val mappings = new HashMap[String, () => Any]
def get(path: String)(action: => Any) = mappings += path -> (() => action)
def handle(exchange: HttpExchange) = mappings.get(exchange.getRequestURI.getPath) match {
case None => respond(exchange, 404)
case Some(action) => try {
respond(exchange, 200, action().toString)
} catch {
case ex: Exception => respond(exchange, 500, ex.toString)
}
}
}
class HelloApp extends SimpleHttpServer {
var count = 0
get("/") {
"There's nothing here"
}
get("/hello") {
"Hello, world!"
}
get("/markup") {
<html>
<head>
<title>Test Title</title>
</head>
<body>
Test Body
</body>
</html>
}
def countPage = <html>
<head>
<title>Test Title</title>
</head>
<body>
Count:
{count}<a href="/increaseCount">++</a>
<a href="/decreaseCount">--</a>
<a href="/resetCount">Reset</a>
</body>
</html>
get("/count") {
countPage
}
get("/resetCount") {
count = 0
redirect("/count")
}
get("/increaseCount") {
count = count + 1
redirect("/count")
}
get("/decreaseCount") {
count = count - 1
redirect("/count")
}
get("/error") {
throw new RuntimeException("Bad bad error occurred")
}
}
object Main {
def main(args: Array[String]) {
val server = new HelloApp()
server.start()
}
}