Elixir Plug: 使用Plug開發Web應用程序

須要一些 Elixir 的基礎. html

對於沒有Erlang背景知識的同窗, 有比較陡峭的學習曲線. 可是Elixir語言提供了一個庫: Plug, 用它咱們可以開發基於Erlang VM的Web應用.git

本文采用 Cowboy 做爲Web服務器, 來構造一個超級簡單的Web應用. 它惟一的功能就是在瀏覽器上顯示一個純文本: "Hello World!". Plug 不是一個Web框架, 它不是用來替代 PhoenixSugar 的, 相反,這兩個框架都使用了Plug來與底層的HTTP服務器(Cowboy)交互.github

快速上手

經過命令mix new --sup plug_sample 建立一個項目.web

mix.exs文件中添加依賴json

defp deps do
  [{:cowboy, "~> 1.0.0"},
   {:plug, "~> 0.12"}]
end

安裝依賴api

mix deps.get

:cowboy:plug添加到application函數瀏覽器

def application do
  [applications: [:logger, :cowboy, :plug],
   mod: {PlugSample, []}]
end

啓動Plug

PlugSample.Worker啓動Plug, PlugSample.WorkerPlugSample.start/2啓動服務器

defmodule PlugSample.Worker do
  def start_link do
    Plug.Adapters.Cowboy.http PlugSample.MyPlug, []
  end
end

路由 Plug.Router

建立路由模塊 lib/elixir_plug_examples/router.exsession

defmodule ElixirPlugExamples.Router do
  use Plug.Router
  if Mix.env == :dev do
    use Plug.Debugger
  end
  plug :match
  plug :dispatch
  # Root path
  get "/" do
    send_resp(conn, 200, "This entire website runs on Elixir plugs!")
  end
end

路由模塊建立完成後, 就能夠經過iex -S mix來啓動這個簡單的Web應用程序了. 訪問 http://localhost:4000/.app

使用 curl -v http://localhost:4000 鏈接到服務器, -v 選項讓咱們能夠看到響應頭信息.

響應頭以下:

> GET / HTTP/1.1
> Host: localhost:4000
> User-Agent: curl/7.43.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< server: Cowboy
< date: Tue, 12 Apr 2016 08:25:38 GMT
< content-length: 11
< cache-control: max-age=0, private, must-revalidate
< content-type: text/plain; charset=utf-8
< 
Hello world

完整的代碼

本文網站的示例代碼

https://github.com/developerworks/plug_sample

Plug 是什麼?

  • Plug 是一段代碼片斷, 它通常插入到請求處理鏈條中的一個特定位置.

  • 多個Plug構成一個完整的處理鏈條

  • 請求首先被轉換成%Plug.Conn{}結構, 並傳遞個鏈條中的第一個Plug, 第一個Plug處理(修改,增長,刪除)完成後, 傳遞給後續的Plug

plug.png

兩種類型的Plug

  • 函數的Plug
    函數Plug是一個接受%Plug.Conn和一個選項列表做爲參數, 並返回一個%Plug.Conn函數, 例如:

    def my_plug(conn, opts) do
      conn
    end
  • 模塊的Plug
    模塊Plug是一個實現了init/1, 和run/2函數的模塊:

    module MyPlug do
      def init(opts) do
        opts
      end
    
      def call(conn, opts) do
        conn
      end
    end

模塊Plug有一個特色是: init/1在編譯時運行, run/2在運行時運行. 由init/1返回的值會被傳遞給run/2. 所以儘可能吧繁重的工做安排到init/1去執行對Plug的性能有很是大的提高.

在Phoenix中, 可使用管道pipeline把多個Plug組合到一塊兒.

好比:

針對瀏覽器的管道(輸出HTML):

pipeline :browser do
  plug :accepts, ["html"]
  plug :fetch_session
  plug :fetch_flash
  plug :protect_from_forgery
  plug :put_secure_browser_headers
end

針對API接口的管道(輸出JSON)

pipeline :api do
  plug :accepts, ["json"]
end

Plug 的測試

Plug提供了一個Plug.Test模塊簡化Plug的測試, 下面是一個例子

defmodule MyPlugTest do
  use ExUnit.Case, async: true
  use Plug.Test
  @opts AppRouter.init([])
  test "returns hello world" do
    # Create a test connection
    conn = conn(:get, "/hello")
    # Invoke the plug
    conn = AppRouter.call(conn, @opts)
    # Assert the response and status
    assert conn.state == :sent
    assert conn.status == 200
    assert conn.resp_body == "world"
  end
end

可用的Plugs

Plug Types Description
Plug.CSRFProtection 添加跨站點請求保護, 若是要使用Plug.Session,
這個是必須的;
Plug.Head HEAD請求轉換爲GET請求;
Plug.Logger 記錄請求;
Plug.MethodOverride 重寫指定在請求頭中指定的方法;
Plug.Parsers 根據Content-Type負責解析請求體;
Plug.RequestId 設置一個請求ID, 用在日誌中;
Plug.Session 處理會話管理和存儲;
Plug.SSL 強制請求經過SSL;
Plug.Static 處理靜態文件;
Plug.Debugger 調試頁面
Plug.ErrorHandler 容許開發者定製錯誤頁面, 而不是發送一個空頁面.
相關文章
相關標籤/搜索