2017-06-14 49 views
1

我的目標是能夠在phoenix控制器內處理分塊的HTTP請求。我認爲解決方案是使用Plug.Conn.read_body但是我收到錯誤或超時。如何在phoenix控制器中讀取小塊數據,使用Plug.Conn

目前我認爲最好的解決方案是自定義解析器。

defmodule Plug.EventStreamParser do 
    @behaviour Plug.Parsers 
    alias Plug.Conn 

    def parse(conn, "text", "event-stream", _headers, _opts) do 
    Conn.read_body(conn, length: 2, read_length: 1, read_timeout: 1_000) 
    |> IO.inspect 
    {:ok, %{}, conn} 
    end 
end 

但是我總是在檢查行得到{:error :timeout}

+1

你沒讀完的請求。你只是讀1個字節。 – Aetherus

+0

你想一次讀多少數據?一次1個字節直到完成? – Dogbert

+0

我們正在發送一個請求中的事件流,我想要讀取每個SSE來單獨處理 –

回答

3

Plug.Conn.read_body/2只讀取請求主體的一個塊。您需要遞歸調用它才能讀取所有內容。你也不需要寫一個解析器來閱讀大塊的正文(如果我正確理解你的問題,我不認爲解析器甚至可以這樣做)。如果請求的Content-Type不是默認情況下Plug解析的請求,則可以從控制器調用Plug.Conn.read_body/2

這裏有一個小的實現的遞歸從控制器調用Plug.Conn.read_body/2

defmodule MyApp.PageController do 
    use MyApp.Web, :controller 

    def index(conn, _params) do 
    {:ok, conn} = read_body(conn, [length: 1024, read_length: 1024], fn chunk -> 
     # We just print the size of each chunk we receive. 
     IO.inspect byte_size(chunk) 
    end) 
    text conn, "ok" 
    end 

    def read_body(conn, opts, f) do 
    case Plug.Conn.read_body(conn, opts) do 
     {:ok, binary, conn} -> 
     f.(binary) 
     {:ok, conn} 
     {:more, binary, conn} -> 
     f.(binary) 
     read_body(conn, opts, f) 
     {:error, term} -> 
     {:error, term} 
    end 
    end 
end 

這在大約1024字節的塊讀取主體(它不保證返回的二進制是完全一樣大小的要求)。隨着下面的請求登載有4000個字節:

$ head -c 4000 /dev/urandom | curl -XPOST http://localhost:4000 --data-binary @- -H 'Content-Type: application/vnd.me.raw' 
ok 

以下是記錄到控制檯:

[info] POST/
[debug] Processing by MyApp.PageController.index/2 
    Parameters: %{} 
    Pipelines: [:api] 
1024 
1024 
1024 
928 
[info] Sent 200 in 3ms 
相關問題