Reputation: 1339
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 the index.html
file;/some/file.html
should serve the file.html
file from the some
directory provided the path exists and 404 if it doesn't;/some/
should send back a 403 or a 404 to prevent directory listing/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:
/
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 /
).static
pipeline in router.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:
# 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)
...
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.
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
Upvotes: 2
Views: 1963
Reputation: 665
I had your same problem, I was trying to serve a SPA created using create-react-app, and I put all the generated files in the priv/static
folder.
The only way I find to serve the static index.html file from the root path is the following:
only:
option form the Static.Plug
in the endpoint.ex file as you did.In particular, in the router.ex
file, under the "/"
scope, I have the following route defined:
get "/", PageController, :index
In the PageController, I implemented the index method as follows:
def index(conn, _params) do
file = File.read!("priv/static/index.html")
html(conn, file)
end
I don't know exaclty what is the mechanic behind the Static Plug, but I found this workaround acceptable for my use case.
I hope this could help you as well.
Upvotes: 2