2017-06-14 2 views
1

Mon but est de pouvoir traiter une requête HTTP en bloc dans un contrôleur phoenix. Je pense que la solution est d'utiliser Plug.Conn.read_body mais je reçois une erreur ou un délai d'attente.Comment lire de petites portions de données dans le contrôleur phoenix, en utilisant Plug.Conn

Actuellement, je pense que la meilleure solution est un analyseur personnalisé.

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 

Cependant, je reçois toujours le {:error :timeout} à la ligne d'inspection.

+1

Vous n'avez pas fini de lire la demande. Vous venez de lire 1 octet. – Aetherus

+0

Combien de données voulez-vous lire en même temps? 1 octet à la fois jusqu'à la fin? – Dogbert

+0

Nous envoyons un flux d'événements dans une requête, je veux lire chaque SSE à traiter individuellement –

Répondre

3

Plug.Conn.read_body/2 lit uniquement un segment du corps de la demande. Vous devez l'appeler récursivement afin de tout lire. Vous n'avez pas non plus besoin d'écrire un analyseur pour simplement lire le corps en morceaux (je ne pense pas qu'un analyseur peut même le faire si je comprends bien votre question); Si le Content-Type de la requête n'est pas un plug-in par défaut, vous pouvez appeler Plug.Conn.read_body/2 à partir de votre contrôleur.

Voici une petite mise en œuvre de l'appel récursive Plug.Conn.read_body/2 d'un contrôleur:

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 

Ce lit le corps en morceaux d'environ 1024 octets (il est pas garanti que le binaire retourné est exactement la même taille que demandé). Avec la requête suivante que 4000 octets: POSTs

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

Ce qui suit est connecté à la console:

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