2016-07-08 3 views
0

Ich dachte daran, Phoenix zu überspringen, da ich gerade plane, eine Demo für eine React-App zu erstellen, die für ihren Status einige API-Routen verwendet. Scheint wie eine Gelegenheit, sich mit der zugrunde liegenden Technologie vertraut zu machen.Wie können Sie beliebige Pfade zu Dateien für Plug.Static-Dateien korrekt umleiten?

Ich habe folgendes herausgefunden, aber es fühlt sich sehr "hart codiert" an und ich bin neugierig, ob es eine elegantere Lösung gibt, um dasselbe zu erreichen.

defmodule DemoApp.Plug.ServeStatic do 
    use Plug.Builder 

    @static_opts [at: "/", from: "priv/static"] 

    plug :default_index 
    plug Plug.Static, @static_opts 
    plug :default_404 
    plug Plug.Static, Keyword.put(@static_opts, :only, ["error_404.html"]) 

    # Rewrite/to "index.html" so Plug.Static finds a match 
    def default_index(%{request_path: "/"} = conn, _opts) do 
    %{conn | :path_info => ["index.html"]} 
    end 
    def default_index(conn, _), do: conn 

    # Rewrite everything that wasn't found to an existing error file 
    def default_404(conn, _opts) do 
    %{conn | :path_info => ["error_404.html"]} 
    end 
end 

Die Idee ist /index.html ohne Umleitung dienen haben, und dient den Inhalt einer Fehlerdatei, wenn etwas nicht, statt einer minimalen Antwort „404 Datei nicht gefunden“ string gefunden.

Gibt es eine Möglichkeit, dies zu erreichen, ohne Plug.Static zweimal zu verbinden, oder ist das der richtige Weg? Ich kann auch sehen, dass der Catchall :default_404 später mit meinen API-Routen kollidiert, und ich bin mir nicht sicher, wie ich das lösen würde.

Jeder Eingang würde sehr geschätzt werden. Vielen Dank!

Antwort

3

Ich würde dafür Plug.Router und Plug.Conn.send_file/5 verwenden. Hier einige Code, der das tut, was Sie tun, aber viel sauberer:

defmodule M do 
    use Plug.Router 

    plug Plug.Static, at: "/", from: "priv/static" 
    plug :match 
    plug :dispatch 

    get "/" do 
    send_file(conn, 200, "priv/static/index.html") 
    end 

    match _ do 
    send_file(conn, 404, "priv/static/404.html") 
    end 
end 

Als :match und :dispatch angeschlossen sind nach Plug.Static, werden alle Dateien in priv/static wird, bevor fallen zurück an den Router bedient werden, wie Phoenix tut.

Mit diesen Dateien in priv/static:

➜ cat priv/static/404.html 
404.html 
➜ cat priv/static/index.html 
index.html 
➜ cat priv/static/other.html 
other.html 

Hier ist, wie dieser Code funktioniert:

➜ curl http://localhost:4000 
index.html 
➜ curl http://localhost:4000/ 
index.html 
➜ curl http://localhost:4000/index.html 
index.html 
➜ curl http://localhost:4000/other.html 
other.html 
➜ curl http://localhost:4000/foo 
404.html 
➜ curl http://localhost:4000/foo/bar 
404.html 
➜ curl http://localhost:4000/404.html 
404.html 
➜ curl -s -I http://localhost:4000/foo | grep HTTP 
HTTP/1.1 404 Not Found 
➜ curl -s -I http://localhost:4000/foo/bar | grep HTTP 
HTTP/1.1 404 Not Found 
➜ curl -s -I http://localhost:4000/404.html | grep HTTP 
HTTP/1.1 200 OK 
+0

Danke, das ist genau das, was ich gesucht habe! Ich habe die "Plug.Router" -Dokumente überprüft und ich benutzte die eingebaute Pipeline in einem OP, aber ich vergaß völlig, dass ich auch alle 'Plug.Conn'-Methoden zur Verfügung hatte. Sehr geschätzt. – MildlySerious

+1

Ein Problem mit diesem Ansatz ist, dass 'send_file' nicht alle Funktionen von' Plug.Static' hat, wie das Setzen von Caching-Headern wie 'ETag'. Gibt es eine Möglichkeit, den Pfad des Conn einfach neu zu schreiben und die modifizierte Anfrage an 'Plug.Static' weiterzuleiten? – denisw

Verwandte Themen