Open jdukewich opened 1 year ago
I came up with a workaround that uses a custom service that wraps ServeDir
as the fallback. The custom service will always add .html to the request path
use std::convert::Infallible;
use std::task::{Context, Poll};
use axum::http::{Request, Response};
use axum::body::Bytes;
use http_body::Body;
use tower::Service;
use tower_http::services::ServeDir;
/// Service that automatically adding .html extension to requests
#[derive(Debug, Clone)]
pub struct AddHtmlExtService<Fallback>(pub ServeDir<Fallback>);
impl<ReqBody, F, FResBody> Service<Request<ReqBody>> for AddHtmlExtService<F>
where
F: Service<Request<ReqBody>, Response = Response<FResBody>, Error = Infallible> + Clone,
F::Future: Send + 'static,
FResBody: Body<Data = Bytes> + Send + 'static,
FResBody::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
{
type Response = <ServeDir<F> as Service<Request<ReqBody>>>::Response;
type Error = <ServeDir<F> as Service<Request<ReqBody>>>::Error;
type Future = <ServeDir<F> as Service<Request<ReqBody>>>::Future;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
<ServeDir<F> as Service<Request<ReqBody>>>::poll_ready(&mut self.0, cx)
}
fn call(&mut self, mut req: Request<ReqBody>) -> Self::Future {
// this removes the scheme and authority, but it's ok since ServeDir doesn't care
if let Ok(uri) = format!("{}.html", req.uri().path()).parse() {
*req.uri_mut() = uri;
}
self.0.call(req)
}
}
To compose the service:
let service = ServeDir::new("foo").fallback(AddHtmlExtService(ServeDir::new("foo")))
When this service encounters /register
, it cannot find the file, so it will call the fallback. The fallback will call the inner service with /register.html
which succeeds.
I don't know if this works for all cases, but from some simple testing it seems to work. Also this can probably be a bit more efficient if it is built in to ServeDir
Feature Request
Motivation
Next.js Static Export results in a
/out
directory that looks something likeThis differs slightly from a traditional SPA where all routes would go to index.html, as a request to
/register
should use theregister.html
file.There may be a way to accomplish what I'm asking, but I couldn't figure it out from the docs and/or examples. I tried use ServeDir as so
Going to
/
correctly returns the index page. Going to/register.html
correctly returns the register page. But I want/register
to also return the register page, but it returns 404Proposal
For a given path without any extension, attempt to append
.html
. Similar to append_index_html_on_directories, but could have something such asappend_html_on_directories
where it would only append".html"
rather than"index.html"
to the path.Alternatives
Not sure of any.