I'm working on an API server implemented with the Phoenix Framework. JSON APIs are served from the /api/<version>
URL. The server also needs to serve static .html
(and others, .css
, .js
, etc.) files from /
: it's actually a little SPA developed in another language and compiled down to HTML5, JS and CSS. The behavior should be:
/
should serve theindex.html
file;/some/file.html
should serve thefile.html
file from thesome
directory provided the path exists and 404 if it doesn't;- URLs like
/some/
should send back a 403 or a 404 to prevent directory listing - everything under
/api
is managed by dedicated controllers.
The project is generated with mix phx.new --no-ecto --no-html --no-gettext --no-webpack static
to get rid of .css
, .js
files and of the templates. I also created a priv/static
directory for the statics assets.
I had to remove only: ~w(css fonts images js favicon.ico robots.txt)
from the parameter list of plug Plug.Static
in endpoint.ex
to have files at the root URL being served. All works fine except the errors:
- a request on
/
displays the Phoenix error page with the log[debug] ** (Phoenix.Router.NoRouteError) no route found for GET / (StaticWeb.Router)
. I added{:plug_static_index_html, "~> 1.0"}
so I got rid of that problem, yet invoking/subdir
sends back Phoenix error page. I just don't see where and how to tell Phoenix to send back a 403 or a 404 (except for/
). - Invoking a URL on a non-exiting file does not send back a 404 but rather the Phoenix error page. I tried to create a
static
pipeline inrouter.ex
but it seems the flow doesn't get there. The documentation states: If a static asset cannot be found,Plug.Static
simply forwards the connection to the rest of the pipeline. but I don't see where to put the 404 reply.
Here are the two configurations I tried:
Conf I
# endpoint.ex
...
# Serve at "/" the static files from "priv/static" directory.
plug Plug.Static.IndexHtml, at: "/"
plug Plug.Static,
at: "/",
from: :static,
gzip: false
# only: ~w(css fonts images js favicon.ico robots.txt)
...
Conf II
I removed every thing concerning static content from endpoint.ex
and added a static
pipeline in router.ex
# router.ex
...
pipeline :static do
plug :put_secure_browser_headers
plug Plug.Static,
at: "/",
from: :static,
gzip: false # ,
# only: ~w(css fonts images js favicon.ico robots.txt)
plug :not_found
end
scope "/", staticWeb do
pipe_through :static
end
def not_found(conn, _) do
send_resp(conn, 404, "not found")
end
...
Any hint would be helpful.
Update on 13th of August 2020
Added a catch all rule on scope "/"
at the end of router.ex
and at least I get a 404 for any wrong request. I'm just wondering how clean all this is...
# router.ex
...
scope "/", AlaaarmWeb do
match :*, "/*path", DefController, :error_404
end