2016年1月24日星期日

Plug

什么是Plug?

看下github上说的:
A plug takes two shapes. It is a function that receives a connection and a set of options as arguments and returns the connection or it is a module that provides an init/1 function to initialize options and implement the call/2 function, receiving the connection and the initialized options, and returning the connection.
这个基本上是一段英文绕口令。。。
大致说一个plug就是
* 一个函数 或者
* 一个模块

函数

入参为
1. connection
2. 一组选项(options)
返回
1. connection

模块

这块模块提供了两个函数, 一个是 init/1 一个是 call/2。init 初始化选项(options),call 入参为 connection 还有 初始化了的选项(options)返回一个connection

这样看下来Plug类似一个middleware。

connection

Plug.Conn struct描述一个connection
elixir
%Plug.Conn{host: "www.tiddr.de",
path_info: ["bar", "baz"],
...}

数据可以从这个结构体里直接读出, 或者用 pattern match。一般使用 Plug.Conn 提供的函数来操作 connection。比如 put_resp_content_type/2 send_resp/3 等等。

需要注意的是 connection 是不可修改的 immutable

Finally, keep in mind that a connection is a direct interface to the underlying web server. When you call send_resp/3 above, it will immediately send the given status and body back to the client. This makes features like streaming a breeze to work with.

文档这段看懂了,没看明白。 没有缓存?

Plug Router

一个Plug Router就是一个 plug,他还有自己的 plug 管道。
```elixir

defmodule AppRouter do
use Plug.Router
plug :match
plug :dispatch

get /hello do
send_resp(conn, 200, TTTing)
end

match _ do
send_resp(conn, 404, oops)
end
end
``
这个例子里,会先调用
matchplug,之后再调用dispatch` plug。match 找出处理的函数, dispatch 执行这个函数。
路由是放在一个查找里的, 所以比线性查找要快的多。

测试 plugs

Plug自带了一个 Plug.Test 模块用来方便测试plug。
```elixir
defmodule PlugTestTest do
use ExUnit.Case
use Plug.Test

@opts AppRouter.init([])

test return hello world do
conn = conn(:get, /hello)
conn = AppRouter.call(conn, @opts)
assert conn.state == :sent
assert conn.status == 200
assert conn.resp_body == TTTing
end
end
```

可用的Plugs

Plug 包提供了很多的 plugs
1. Plug.CSRFProtection - 提供 SCRF 包含, 当你用 Plug.Session 的时候会需要他
2. Plug.Head - 把 HEAD 头改为 GET (不知道为了什么?)
3. Plug.Logger - 日志请求
4. Plug.MethodOverride - 用头里定义的方法重载request的method (?)
5. Plug.Parsers - 根据 content-type 解析 request body
6. Plug.RequestId - 为log设置一个request ID
7. Plug.Session - session管理、存储
8. Plug.SSL - 强制要求request走SSL
9. Plug.Static - 静态文件服务

帮助模块

  1. Plug.Debugger - 当处理request出错的时候显示调试信息
  2. Plug.ErrorHandler - 出错的时候显示制定的错误页面