如何使用 Warp 服务 CSS 和 JS 文件?

How to serve CSS and JS files using Warp?

我希望 Warp 为当前工作目录提供服务。这是整个 main.rs:

#[tokio::main]
async fn main() {
    let current_dir = std::env::current_dir().expect("failed to read current directory");
    warp::serve(warp::fs::dir(current_dir))
        .run(([127, 0, 0, 1], 3030))
        .await;
}

具有以下依赖项:

[dependencies]
tokio = { version = "1.5", features = ["full"] }
warp = "0.3"

然后我 运行 它在目录 www 上,结构如下:

www
├── foo
|   └── index.html
|   └── style.css
└── bar
    └── index.html
    └── style.css

已提供 HTML 页面,但未提供其引用的 CSS 文件。 HTML 页面使用 <link rel="stylesheet" href="style.css">

引用各自的 CSS 文件

我使用 node.js express 进行此工作,但使用 Warp 时它会尝试加载 www/style.css,而不是 www/foo/style.csswww/bar/style.css

如果我将 href 更改为 "foo/style.css""bar/style.css",它会起作用,但我想尽可能避免这种情况。有什么我可以在 Warp 的末端改变来解决这个问题吗?

编辑: 我了解到,如果 URL 包含尾部斜杠,页面会正确呈现 CSS。

所以这行不通:

http://localhost:3030/foo
http://localhost:3030/bar

但是这样做:

http://localhost:3030/foo/
http://localhost:3030/bar/

感谢@Kitsu 的comment for a similar question, I learned that this is currently an open issue

我最终使用了那个讨论中 kolektiv's solution 的略微修改版本。它使用 warp::path::full() 获取路径,然后在需要时使用尾部斜杠重定向。这是我的示例的预期代码。

cargo.toml 的依赖项:

[dependencies]
tokio = { version = "1.5", features = ["full"] }
warp = "0.3"

main.rs:

use std::str::FromStr;
use warp::{filters::BoxedFilter, http::Uri, path::FullPath, redirect, Filter, Reply};

#[tokio::main]
async fn main() {
    let current_dir = std::env::current_dir().expect("failed to read current directory");

    let routes = root_redirect().or(warp::fs::dir(current_dir));

    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;
}

fn root_redirect() -> BoxedFilter<(impl Reply,)> {
    warp::path::full()
        .and_then(move |path: FullPath| async move {
            let path = path.as_str();

            // do not redirect if the path ends in a trailing slash
            // or contains a period (indicating a specific file, e.g. style.css)
            if path.ends_with("/") || path.contains(".") {
                return Err(warp::reject());
            }

            Ok(redirect::redirect(
                Uri::from_str(&[path, "/"].concat()).unwrap(),
            ))
        })
        .boxed()
}