sujingjhong.com


Elixir 101 / 快速建立 HTTP 伺服器

在 Elixir 裡要怎麼架設 HTTP 伺服器呢?

在 NodeJS 架設 HTTP 伺服器 #

如果是在 NodeJS 底下,我們可以很快透過以下的程式碼建立簡單的伺服器:

const http = require('http');

function serverHandler(req, res){
  switch (req.url){
    case '/':{
      res.writeHead(200, {'Content-Type':'text/html'});
      res.write('Hello world');
      res.end();
      break;
    }
      
    default:{
      res.writeHead(404, {'Content-Type':'text/html'});
      res.end('Not found');
      break;
    }
  }
}

const server = http.createServer(serverHandler);
server.listen(3001);

但通常我們在 NodeJS 裡面不會這樣直接呼叫 http.createServer 來建立伺服器,我們會利用一些 Web 框架來幫助我們,讓開發上更加便利,例如 express,例如上述程式碼可以改成:

const server = require('express')();

server.get('/', function (req, res) {
  res.send('Hello World')
});

server.listen(3000);

在 Elixir 中架設伺服器 #

所以一樣的,在 Elixir 中,我們透過一套名為 plug 的中間層套件,協助我們架設伺服器。

首先我們先建立一個乾淨的專案,並且啟用 supervision 模式:

$ mix new http_server --sup

讓我們看一下資料夾結構:

.
├── README.md
├── lib
│   ├── http_server
│   │   └── application.ex
│   └── http_server.ex
├── mix.exs
└── test
    ├── http_server_test.exs
    └── test_helper.exs

安裝 plug #

首先我們需要先安裝 plug。在 Elixir 安裝套件很簡單。

先讓我們打開資料夾中的 mix.exs 檔案,他內容會長這樣:

defmodule HttpServer.MixProject do
  use Mix.Project

  def project do
    [
      app: :http_server,
      version: "0.1.0",
      elixir: "~> 1.9",
      start_permanent: Mix.env() == :prod,
      deps: deps()
    ]
  end

  # Run "mix help compile.app" to learn about applications.
  def application do
    [
      extra_applications: [:logger],
      mod: {HttpServer.Application, []}
    ]
  end

  # Run "mix help deps" to learn about dependencies.
  defp deps do
    [
      # {:dep_from_hexpm, "~> 0.3.0"},
      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
    ]
  end
end

然後讓我們看到 defp deps do 這段函式區塊:

# Run "mix help deps" to learn about dependencies.
defp deps do
	[
		# {:dep_from_hexpm, "~> 0.3.0"},
		# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
	]
end

我們在他的 [] 的陣列裡加入 {:plug_cowboy, "~> 2.0"},這時候應該會長這個樣子:

# Run "mix help deps" to learn about dependencies.
defp deps do
	[
		{:plug_cowboy, "~> 2.0"}
	]
end

首頁顯示 Hello World #

安裝完後,我們在 lib 資料夾底下,建立一個檔案名為 router.ex,然後裡面寫入:

defmodule Router do
  import Plug.Conn

  def init(options) do
    options
  end

  def call(conn, _opts) do
    conn
    |> put_resp_content_type("text/plain")
    |> send_resp(200, "Hello world")
  end
end

讓伺服器隨同程式上線 #

再來,我們必須讓伺服器隨著程式啟用時上線。所以我們要來更改 lib/http_server/application.ex 檔案。他應該會長這樣:

defmodule HttpServer.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  def start(_type, _args) do
    children = [
      # Starts a worker by calling: HttpServer.Worker.start_link(arg)
      # {HttpServer.Worker, arg}
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: HttpServer.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

我們在 start 函式中的 children 陣列加入一行:

{Plug.Cowboy, scheme: :http, plug: Router, options: [port: 4001]}

他就變成:

children = [
	{Plug.Cowboy, scheme: :http, plug: Router, options: [port: 4001]}
]

執行程式 #

程式碼都修改好後,我們在終端機打上:

$ mix run --no-halt

如果沒有東西話記得先切到 http_server 底下:

$ cd http_server

最後打開瀏覽器,輸入 http://localhost:4001,就大功告成啦!

hello world 網頁

參考文獻 #