在 Scala 中引导 Web 服务器

发布于 2024-10-02 05:25:12 字数 349 浏览 3 评论 0原文

使用 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 行代码即可运行 Web 服务器,这确实令人印象深刻。

Scala 的等价物是什么?

The following is possible using 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 commands and 7 lines of code to get a web server running is very impressive indeed.

What's the Scala equivalent?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

违心° 2024-10-09 05:25:12

这使用了 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()
  }
}

This uses the HttpServer class that is built-in in JDK6. Feel free to suggest improvements, I'm new to 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()
  }
}
尝蛊 2024-10-09 05:25:12

我知道Max已经提到它,但我忍不住指出Scalatra 的 6行hello world:

import org.scalatra._

class ScalatraExample extends ScalatraServlet {
  get("/") {
    <h1>Hello, world!</h1>
  }
}

无论如何,看看可用的 Scala Web 框架

编辑

有一些关于准备工具有多容易的讨论,特别是在 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

There, web server running。当然,你必须事先了解 SBT 和 Lifty,甚至知道你会使用它们来运行 Scala Lift 程序,但是,另一方面,我从未听说过 Flask,所以我肯定会花很多钱我花更多的时间尝试弄清楚如何使用 Python 运行 Web 服务器应用程序,而不是使用 Lift 应用程序。

我在第一次尝试时也没有得到正确的结果——我尝试使用 Scala 2.8.1(上面使用默认的 2.7.7 版本,尽管 2.8.0 也可以),却发现没有 Lift 版本目前该版本的 Scala 可用。另一方面,我已经安装了 lifty,然后将其卸载只是为了显示安装它的命令。

我确实希望有一个用于 SBT 的 Debian/Ubuntu 软件包——毕竟,它只是一个很小的 ​​shell 脚本和一个 jar 文件,并且它负责下载 Scala、Lift 等以及您需要的任何版本。

它是与 Python 和 Ruby 不同的模型,Python 和 Ruby 语言带有一个包管理器来处理大多数事情。

I know Max alread mentioned it, but I couldn't resist pointing out Scalatra's 6 lines hello world:

import org.scalatra._

class ScalatraExample extends ScalatraServlet {
  get("/") {
    <h1>Hello, world!</h1>
  }
}

Anyway, take a look at available Scala web frameworks.

EDIT

There's some discussion about how easy is to get the tooling ready, particularly with regards to Lift. So, here's a session on Ubuntu. Most of my time was spent trying to figure out where did Sun's Java go in the package manager. Anyway, once Java was installed, this is how it went, with all messages elided, so one can see what I actually had to type:

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

There, web server running. Of course, you have to know about SBT and Lifty beforehand, to even know you'd use them to get a Scala Lift program running, but, on the other hand, I had never heard about Flask, so I'd certainly spend way more time trying to figure out how to get a web server application going in Python than I did getting a Lift one.

I also did not get it right on the first try -- I tried going for Scala 2.8.1 (the above uses a default 2.7.7 version, though 2.8.0 will work too), only to find out that there's no Lift version available for that version of Scala as yet. On the other hand, I had lifty installed already, and de-installed it just to show the command that installs it.

I do wish there was a Debian/Ubuntu package for SBT -- it's just a tiny shell script and a jar file, after all, and it takes care of downloading Scala, Lift, etc, and at whatever version you need.

It is a different model than Python and Ruby, where the language comes with a package manager which handles most things.

迷路的信 2024-10-09 05:25:12

您可能会发现 Unfiltered 值得一看。

You might find Unfiltered worth a look.

帅的被狗咬 2024-10-09 05:25:12

嗯,有 Scalatra,它的目标是在功能和易用性方面类似于 Ruby 的 Sinatra。

Well, there's Scalatra, which aims to be analogous to Ruby's Sinatra in terms of functionality and ease of use.

执手闯天涯 2024-10-09 05:25:12

此解决方案使用 JAX-WS 端点:

import java.io._
import javax.xml.ws._
import javax.xml.ws.http._
import javax.xml.transform._
import javax.xml.transform.stream._

@WebServiceProvider
@ServiceMode(value=Service.Mode.PAYLOAD)
class P extends Provider[Source] {
  def invoke(source: Source) = new StreamSource( new StringReader("<p>Hello There!</p>"));
}

val address = "http://127.0.0.1:8080/"
Endpoint.create(HTTPBinding.HTTP_BINDING, new P()).publish(address)

println("Service running at "+address)
println("Type [CTRL]+[C] to quit!")

Thread.sleep(Long.MaxValue)

您可以将其复制到文件 WebServer.scala 并只需键入以下内容即可运行它:

scala WebServer.scala

This solution uses a JAX-WS Endpoint:

import java.io._
import javax.xml.ws._
import javax.xml.ws.http._
import javax.xml.transform._
import javax.xml.transform.stream._

@WebServiceProvider
@ServiceMode(value=Service.Mode.PAYLOAD)
class P extends Provider[Source] {
  def invoke(source: Source) = new StreamSource( new StringReader("<p>Hello There!</p>"));
}

val address = "http://127.0.0.1:8080/"
Endpoint.create(HTTPBinding.HTTP_BINDING, new P()).publish(address)

println("Service running at "+address)
println("Type [CTRL]+[C] to quit!")

Thread.sleep(Long.MaxValue)

You can copy it to a file WebServer.scala and run it simply by typing:

scala WebServer.scala
请持续率性 2024-10-09 05:25:12

您可以使用嵌入式 Jetty 服务器:

/*
 * Required Libs: Jetty, Servlet API
 *
 * Compile:
 *   scalac -cp jetty-6.1.14.jar:jetty-util-6.1.14.jar:servlet-api-2.5-6.1.14.jar WebServer.scala
 *
 * Run:
 *  scala -cp .:jetty-6.1.14.jar:jetty-util-6.1.14.jar:servlet-api-2.5-6.1.14.jar WebServer
 */
import org.mortbay.jetty.Server
import org.mortbay.jetty.servlet.Context
import javax.servlet.http.{HttpServlet,
                       HttpServletRequest, 
                       HttpServletResponse}

class HelloServlet extends HttpServlet {
  override def doGet(req : HttpServletRequest, resp : HttpServletResponse) =
    resp.getWriter().print("Hello There!")
}

object WebServer {
  def main(args: Array[String]) {
    val server = new Server(8080)
    val root = new Context(server, "/", Context.SESSIONS)
    root.addServlet(classOf[HelloServlet], "/*")
    server.start()

    println("Point your browser to http://localhost:8080/")
    println("Type [CTRL]+[C] to quit!")

    Thread.sleep(Long.MaxValue)
  }
}

如果您的目标是进行 LOC 比较,则可以使用嵌入 Sun JDK 的 HTTP 服务器。另一种解决方案可能是使用 javax.xml.ws.Endpoint 和 Provider API。

You could use an embedded Jetty Server:

/*
 * Required Libs: Jetty, Servlet API
 *
 * Compile:
 *   scalac -cp jetty-6.1.14.jar:jetty-util-6.1.14.jar:servlet-api-2.5-6.1.14.jar WebServer.scala
 *
 * Run:
 *  scala -cp .:jetty-6.1.14.jar:jetty-util-6.1.14.jar:servlet-api-2.5-6.1.14.jar WebServer
 */
import org.mortbay.jetty.Server
import org.mortbay.jetty.servlet.Context
import javax.servlet.http.{HttpServlet,
                       HttpServletRequest, 
                       HttpServletResponse}

class HelloServlet extends HttpServlet {
  override def doGet(req : HttpServletRequest, resp : HttpServletResponse) =
    resp.getWriter().print("Hello There!")
}

object WebServer {
  def main(args: Array[String]) {
    val server = new Server(8080)
    val root = new Context(server, "/", Context.SESSIONS)
    root.addServlet(classOf[HelloServlet], "/*")
    server.start()

    println("Point your browser to http://localhost:8080/")
    println("Type [CTRL]+[C] to quit!")

    Thread.sleep(Long.MaxValue)
  }
}

In case you target for a LOC comparison, You use the HTTP server embedded with the Sun JDK. Another solution could be to use javax.xml.ws.Endpoint and the Provider API.

唠甜嗑 2024-10-09 05:25:12

Scala 等效项有 6 个命令:

$ curl https://raw.github.com/n8han/conscript/master/setup.sh | sh
$ ~/bin/cs n8han/giter8
$ ~/bin/g8 scalatra/scalatra-sbt --name=scalatra-example
$ cd scalatra-example
$ wget http://typesafe.artifactoryonline.com/typesafe/ivy-releases/org.scala-tools.sbt/sbt-launch/0.11.0/sbt-launch.jar
$ java -Xmx512M -jar sbt-launch.jar ~jetty-run

使用 Play、

step #1 download Play, then
$ play install scala
$ play new myproject --with scala
$ play run myproject

Scala equivalent is in 6 commands:

$ curl https://raw.github.com/n8han/conscript/master/setup.sh | sh
$ ~/bin/cs n8han/giter8
$ ~/bin/g8 scalatra/scalatra-sbt --name=scalatra-example
$ cd scalatra-example
$ wget http://typesafe.artifactoryonline.com/typesafe/ivy-releases/org.scala-tools.sbt/sbt-launch/0.11.0/sbt-launch.jar
$ java -Xmx512M -jar sbt-launch.jar ~jetty-run

Using Play,

step #1 download Play, then
$ play install scala
$ play new myproject --with scala
$ play run myproject
唠甜嗑 2024-10-09 05:25:12

正如 David Winslow 提到的,Unfiltered 使用代码片段

信息:Apache Spark 字数统计示例的简单 API 功能使用 Unfiltered 用 Scala 编写。

object SimplePlan extends Plan {
  def intent = {
  case req @ GET(Path("/get")) => {
    Ok ~> ResponseString(WordCount.count("Test #1: Test the Default word count program").mkString("\n"));
  }

  case req @ POST(Path("/get_custom")) => {
    val custom_string = Body.string(req)
    Ok ~> ResponseString(WordCount.count(custom_string).mkString("\n"))
  }
 }
}

object SimpleServer extends App {
  val bindingIP = SocketPortBinding(host = "localhost", port = 8080)
  unfiltered.jetty.Server.portBinding(bindingIP).plan(SimplePlan).run()
}

完整示例位于此处

As David Winslow mentioned, Unfiltered usage code snippet

INFO: Simple API capabilities for Apache Spark word count example written in Scala using Unfiltered.

object SimplePlan extends Plan {
  def intent = {
  case req @ GET(Path("/get")) => {
    Ok ~> ResponseString(WordCount.count("Test #1: Test the Default word count program").mkString("\n"));
  }

  case req @ POST(Path("/get_custom")) => {
    val custom_string = Body.string(req)
    Ok ~> ResponseString(WordCount.count(custom_string).mkString("\n"))
  }
 }
}

object SimpleServer extends App {
  val bindingIP = SocketPortBinding(host = "localhost", port = 8080)
  unfiltered.jetty.Server.portBinding(bindingIP).plan(SimplePlan).run()
}

Complete example is here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文