플러그는 다음과 같습니다.
즉, Plug를 사용하면 작은 조각으로 웹 애플리케이션을 구축하고 이를 다른 웹 서버에서 실행할 수 있습니다. 플러그는 Phoenix와 같은 웹 프레임워크에서 요청, 응답 및 웹 소켓을 관리하는 데 사용됩니다. 이 문서에서는 몇 가지 고급 예제를 보여주고 플러그의 주요 구성 요소를 소개합니다.
Plug를 사용하려면 웹 서버와 Plug용 바인딩이 필요합니다. 현재 두 가지 옵션이 있습니다:
mix.exs
에 plug_cowboy
패키지를 추가하여 카우보이 웹서버(Erlang 기반)를 사용하세요.
def deps do
[
{ :plug_cowboy , "~> 2.0" }
]
end
mix.exs
에 bandit
패키지를 추가하여 Bandit 웹서버(Elixir 기반)를 사용하세요:
def deps do
[
{ :bandit , "~> 1.0" }
]
end
이것은 Cowboy 웹서버를 사용하는 최소한의 Hello World 예제입니다.
Mix . install ( [ :plug , :plug_cowboy ] )
defmodule MyPlug do
import Plug.Conn
def init ( options ) do
# initialize options
options
end
def call ( conn , _opts ) do
conn
|> put_resp_content_type ( "text/plain" )
|> send_resp ( 200 , "Hello world" )
end
end
require Logger
webserver = { Plug.Cowboy , plug: MyPlug , scheme: :http , options: [ port: 4000 ] }
{ :ok , _ } = Supervisor . start_link ( [ webserver ] , strategy: :one_for_one )
Logger . info ( "Plug now running on localhost:4000" )
Process . sleep ( :infinity )
해당 스니펫을 파일에 저장하고 elixir hello_world.exs
로 실행하세요. http://localhost:4000/에 접속하면 환영받을 것입니다!
위의 예에서는 MyPlug
라는 첫 번째 모듈 플러그를 작성했습니다. 모듈 플러그는 init/1
함수와 call/2
함수를 정의해야 합니다. call/2
는 init/1
에 의해 반환된 연결 및 옵션과 함께 호출됩니다.
Plug v1.14에는 연결 upgrade
API가 포함되어 있습니다. 이는 즉시 WebSocket 지원을 제공한다는 의미입니다. 이번에는 WebSocket 비트에 대해 Bandit 웹 서버와 websocket_adapter
프로젝트를 사용하는 예를 살펴보겠습니다. 다른 경로가 필요하므로 이를 위해 내장된 Plug.Router
사용합니다.
Mix . install ( [ :bandit , :websock_adapter ] )
defmodule EchoServer do
def init ( options ) do
{ :ok , options }
end
def handle_in ( { "ping" , [ opcode: :text ] } , state ) do
{ :reply , :ok , { :text , "pong" } , state }
end
def terminate ( :timeout , state ) do
{ :ok , state }
end
end
defmodule Router do
use Plug.Router
plug Plug.Logger
plug :match
plug :dispatch
get "/" do
send_resp ( conn , 200 , """
Use the JavaScript console to interact using websockets
sock = new WebSocket("ws://localhost:4000/websocket")
sock.addEventListener("message", console.log)
sock.addEventListener("open", () => sock.send("ping"))
""" )
end
get "/websocket" do
conn
|> WebSockAdapter . upgrade ( EchoServer , [ ] , timeout: 60_000 )
|> halt ( )
end
match _ do
send_resp ( conn , 404 , "not found" )
end
end
require Logger
webserver = { Bandit , plug: Router , scheme: :http , port: 4000 }
{ :ok , _ } = Supervisor . start_link ( [ webserver ] , strategy: :one_for_one )
Logger . info ( "Plug now running on localhost:4000" )
Process . sleep ( :infinity )
해당 스니펫을 파일에 저장하고 elixir websockets.exs
로 실행하세요. http://localhost:4000/에 접속하면 브라우저 콘솔에 메시지가 표시됩니다.
이번에는 웹 애플리케이션에서 사용되는 경로와 모든 요청에 대해 실행될 plug Plug.Logger
플러그와 같은 일련의 단계/플러그를 정의할 수 있는 Plug.Router
사용했습니다.
게다가 보시다시피 Plug는 다양한 웹 서버를 추상화합니다. 애플리케이션을 부팅할 때 Plug.Cowboy
또는 Bandit
선택하는 것의 차이가 있습니다.
지금은 일회용 감독자에서 서버를 직접 시작했지만 프로덕션 배포의 경우 애플리케이션 감독 트리에서 시작하려고 합니다. 다음의 감독되는 핸들러 섹션을 참조하세요.
프로덕션 시스템에서는 애플리케이션의 감독 트리 아래에서 플러그 파이프라인을 시작하려고 할 수 있습니다. --sup
플래그를 사용하여 새 Elixir 프로젝트를 시작합니다:
$ mix new my_app --sup
mix.exs
에 대한 종속성으로 :plug_cowboy
(또는 :bandit
)를 추가하십시오.
def deps do
[
{ :plug_cowboy , "~> 2.0" }
]
end
이제 다음과 같이 lib/my_app/application.ex
업데이트하십시오.
defmodule MyApp.Application do
# See https://hexdocs.pm/elixir/Application.html
# for more information on OTP Applications
@ moduledoc false
use Application
def start ( _type , _args ) do
# List all child processes to be supervised
children = [
{ Plug.Cowboy , scheme: :http , plug: MyPlug , options: [ port: 4001 ] }
]
# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [ strategy: :one_for_one , name: MyApp.Supervisor ]
Supervisor . start_link ( children , opts )
end
end
마지막으로 MyPlug
모듈을 사용하여 lib/my_app/my_plug.ex
생성합니다.
이제 mix run --no-halt
실행하면 http://localhost:4001에서 실행되는 웹 서버로 애플리케이션이 시작됩니다.
Plug.Conn
구조체 Hello World 예제에서는 MyPlug
라는 첫 번째 플러그를 정의했습니다. 플러그에는 모듈 플러그와 기능 플러그의 두 가지 유형이 있습니다.
모듈 플러그는 옵션을 초기화하는 init/1
함수와 연결 및 초기화된 옵션을 수신하고 연결을 반환하는 call/2
함수를 구현합니다.
defmodule MyPlug do
def init ( [ ] ) , do: false
def call ( conn , _opts ) , do: conn
end
함수 플러그는 연결, 옵션 집합을 인수로 사용하고 연결을 반환합니다.
def hello_world_plug ( conn , _opts ) do
conn
|> put_resp_content_type ( "text/plain" )
|> send_resp ( 200 , "Hello world" )
end
연결은 %Plug.Conn{}
구조체로 표현됩니다.
% Plug.Conn {
host: "www.example.com" ,
path_info: [ "bar" , "baz" ] ,
...
}
데이터는 연결에서 직접 읽을 수 있으며 패턴 일치도 가능합니다. 연결 조작은 Plug.Conn
모듈에 정의된 기능을 사용하여 발생하는 경우가 많습니다. 이 예에서는 put_resp_content_type/2
및 send_resp/3
모두 Plug.Conn
에 정의되어 있습니다.
Elixir의 다른 모든 것과 마찬가지로 연결도 불변 이므로 모든 조작은 연결의 새 복사본을 반환한다는 점을 기억하세요.
conn = put_resp_content_type ( conn , "text/plain" )
conn = send_resp ( conn , 200 , "ok" )
conn
마지막으로 연결은 기본 웹 서버에 대한 직접적인 인터페이스 라는 점을 명심하세요. 위에서 send_resp/3
호출하면 주어진 상태와 본문이 즉시 클라이언트에 다시 전송됩니다. 이를 통해 스트리밍과 같은 기능을 쉽게 사용할 수 있습니다.
Plug.Router
들어오는 요청의 경로와 방법을 기반으로 전달하는 "라우터" 플러그를 작성하기 위해 Plug는 Plug.Router
제공합니다.
defmodule MyRouter do
use Plug.Router
plug :match
plug :dispatch
get "/hello" do
send_resp ( conn , 200 , "world" )
end
forward "/users" , to: UsersRouter
match _ do
send_resp ( conn , 404 , "oops" )
end
end
라우터는 플러그입니다. 뿐만 아니라 자체 플러그 파이프라인도 포함되어 있습니다. 위의 예에서는 라우터가 호출되면 로컬(가져온) match/2
함수로 표시되는 :match
플러그를 호출한 다음 일치하는 코드를 실행할 :dispatch
플러그를 호출합니다.
플러그에는 라우터 플러그 파이프라인에 추가할 수 있는 많은 플러그가 함께 제공되므로 경로가 일치하거나 경로가 전달되기 전에 무언가를 연결할 수 있습니다. 예를 들어, 라우터에 로깅을 추가하려면 다음을 수행하세요.
plug Plug.Logger
plug :match
plug :dispatch
참고 Plug.Router
모든 경로를 단일 함수로 컴파일하고 Erlang VM을 사용하여 경로별 경로와 일치하는 선형 조회 대신 기본 경로를 트리 조회로 최적화합니다. 이는 Plug!에서 경로 조회가 매우 빠르다는 것을 의미합니다!
이는 또한 위의 예처럼 catch all match
블록을 정의하는 것이 권장된다는 의미입니다. 그렇지 않으면 (일반 Elixir 함수에서와 마찬가지로) 함수 절 오류로 인해 라우팅이 실패합니다.
각 경로는 플러그 사양에 따라 연결을 반환해야 합니다. 자세한 내용은 Plug.Router
문서를 참조하세요.
플러그에는 플러그를 쉽게 테스트할 수 있는 Plug.Test
모듈이 함께 제공됩니다. 위에서(또는 다른 플러그) 라우터를 테스트하는 방법은 다음과 같습니다.
defmodule MyPlugTest do
use ExUnit.Case , async: true
use Plug.Test
@ opts MyRouter . init ( [ ] )
test "returns hello world" do
# Create a test connection
conn = conn ( :get , "/hello" )
# Invoke the plug
conn = MyRouter . call ( conn , @ opts )
# Assert the response and status
assert conn . state == :sent
assert conn . status == 200
assert conn . resp_body == "world"
end
end
이 프로젝트는 여러 애플리케이션에서 재사용할 수 있는 다양한 플러그를 제공하는 것을 목표로 합니다.
Plug.BasicAuth
- 기본 HTTP 인증을 제공합니다.Plug.CSRFProtection
- 애플리케이션에 사이트 간 요청 위조 방지 기능을 추가합니다. 일반적으로 Plug.Session
사용하는 경우 필요합니다.Plug.Head
- HEAD 요청을 GET 요청으로 변환합니다.Plug.Logger
- 요청을 기록합니다.Plug.MethodOverride
- 요청 매개변수에 지정된 메소드로 요청 메소드를 대체합니다.Plug.Parsers
- 콘텐츠 유형에 따라 요청 본문을 구문 분석하는 일을 담당합니다.Plug.RequestId
- 로그에 사용할 요청 ID를 설정합니다.Plug.RewriteOn
- x-forwarded-*
헤더에서 요청의 호스트/포트/프로토콜을 다시 작성합니다.Plug.Session
- 세션 관리 및 저장을 처리합니다.Plug.SSL
- SSL을 통해 요청을 시행합니다.Plug.Static
- 정적 파일을 제공합니다.Plug.Telemetry
- :telemetry
이벤트를 사용하여 플러그 파이프라인을 계측합니다.우리 문서에서 각각에 대해 더 자세히 알아볼 수 있습니다.
개발에 도움이 되도록 Plug.Router
또는 Plug.Builder
사용한 후 사용할 수 있는 모듈:
Plug.Debugger
- 요청에 실패할 때마다 유용한 디버깅 페이지를 표시합니다.Plug.ErrorHandler
- 개발자가 충돌이 발생한 경우 빈 오류 페이지를 보내는 대신 오류 페이지를 사용자 정의할 수 있습니다. Plug에 기여하고 기존 문제를 해결하는 데 도움을 주는 모든 사람을 환영합니다!
버그 보고서나 기능 요청을 위해 이슈 트래커를 사용하세요. 기여할 준비가 되면 풀 요청을 엽니다. 풀 요청을 제출할 때 CHANGELOG.md
를 업데이트하면 안 됩니다.
문서를 제공할 계획이라면 문서 작성에 대한 모범 사례를 확인하세요.
마지막으로, 공식 공간에서의 모든 상호 작용은 행동 강령을 따른다는 점을 기억하십시오.
나뭇가지 | 지원하다 |
---|---|
v1.15 | 버그 수정 |
v1.14 | 보안 패치만 해당 |
v1.13 | 보안 패치만 해당 |
v1.12 | 보안 패치만 해당 |
v1.11 | 보안 패치만 해당 |
v1.10 | 보안 패치만 해당 |
v1.9 | 2023년 10월부터 지원되지 않음 |
v1.8 | 2023년 1월부터 지원되지 않음 |
v1.7 | 2022년 1월부터 지원되지 않음 |
v1.6 | 2022년 1월부터 지원되지 않음 |
v1.5 | 2021년 3월부터 지원되지 않음 |
v1.4 | 2018년 12월부터 지원되지 않음 |
v1.3 | 2018년 12월부터 지원되지 않음 |
v1.2 | 2018년 6월부터 지원되지 않음 |
v1.1 | 2018년 1월부터 지원되지 않음 |
v1.0 | 2017년 5월부터 지원되지 않음 |
플러그 소스 코드는 Apache License 2.0에 따라 릴리스됩니다. 자세한 내용은 LICENSE 파일을 확인하세요.