【问题标题】:How can I serve static files / a directory in hyper?如何在 hyper 中提供静态文件/目录?
【发布时间】:2017-08-16 20:48:13
【问题描述】:

我想从我的超级服务器提供一些静态文件(.js、.css、...)。
目前我能想到的唯一方法是将文件内联为字符串/在启动时加载它们。
有没有更好的方法来直接提供整个目录或选定的文件?

【问题讨论】:

  • 在实际部署中,您的 nginxcaddy 无论如何都会提供文件,所以我不会太担心这一点,而是设置一个反向代理。
  • @JanNilsFerner 我恭敬地不同意如此广泛的声明。请记住,Rust 是一种系统语言,是一种您可以编写 NGINX 的语言。谁说 OP 没有尝试编写这样的层?
  • @Shepmaster 同意,Rust 将是编写反向代理的理想语言。请注意,我的意思是将我的评论解释为务实的建议,即我认为 OP 可能不会编写下一个 nginx,只是想做一些低级网络,在这种情况下,我建议不要重新发明*并使用他的代码与其他经过验证的解决方案一起使用。
  • 我希望将它放在一个地方。其他框架允许简单地将路径映射到目录。使用 nginx 是一个很好的建议。但我会先尝试在超中进行

标签: server rust hyper


【解决方案1】:

crates.io 中输入单词“hyper static”后,第一个结果是hyper-staticfile。该项目的GitHub repository 有一个examples directory,例如:

extern crate futures;
extern crate hyper;
extern crate hyper_staticfile;
extern crate tokio_core;

// This example serves the docs from target/doc/hyper_staticfile at /doc/
//
// Run `cargo doc && cargo run --example doc_server`, then
// point your browser to http://localhost:3000/

use futures::{Future, Stream, future};
use hyper::Error;
use hyper::server::{Http, Request, Response, Service};
use hyper_staticfile::Static;
use std::path::Path;
use tokio_core::reactor::{Core, Handle};
use tokio_core::net::TcpListener;

type ResponseFuture = Box<Future<Item=Response, Error=Error>>;

struct MainService {
    static_: Static,
}

impl MainService {
    fn new(handle: &Handle) -> MainService {
        MainService {
            static_: Static::new(handle, Path::new("target/doc/")),
        }
    }
}

impl Service for MainService {
    type Request = Request;
    type Response = Response;
    type Error = Error;
    type Future = ResponseFuture;

    fn call(&self, req: Request) -> Self::Future {
        if req.path() == "/" {
            let res = Response::new()
                .with_status(hyper::StatusCode::MovedPermanently)
                .with_header(hyper::header::Location::new("/hyper_staticfile/"));
            Box::new(future::ok(res))
        } else {
            self.static_.call(req)
        }
    }
}

fn main() {
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let addr = "127.0.0.1:3000".parse().unwrap();
    let listener = TcpListener::bind(&addr, &handle).unwrap();

    let http = Http::new();
    let server = listener.incoming().for_each(|(sock, addr)| {
        let s = MainService::new(&handle);
        http.bind_connection(&handle, sock, addr, s);
        Ok(())
    });

    println!("Doc server running on http://localhost:3000/");
    core.run(server).unwrap();
}

【讨论】:

  • 看起来不错。当前唯一的问题是返回值不匹配。 hyper-static 使用 type Future = Box&lt;Future&lt;Item = Response, Error = Error&gt;&gt; 而我使用 type Future = futures::future::FutureResult&lt;Response, Error&gt;