-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Static with fallback #78
Comments
Yep, this seems like it will be a common pattern for frontend-heavy web applications. If a static file exists, serve it, otherwise serve the HTML & JS for the application, which will handle the routing. One complication I see is that we may want Iron to be able to check the URL against a whitelist to know if it is a valid path. If it isn't, then Iron should return a 404. After sketching some pseudocode, I thought of this: let static_files = Static::new("assets");
let remap = Remap::new("assets/index.html")
.get("/users")
.get("/users/:id")
.get("/posts")
.get("/posts/:id");
let fallback = Fallback::new(static_files, remap); This seemingly allows the composition currently favored by the Iron project. Perhaps the |
Something similar to this appears to work: remap.rs use std::collections::HashSet;
use iron::prelude::*;
use iron::{BeforeMiddleware, Url};
pub struct Remap {
new_path: String,
routes: HashSet<&'static str>,
}
impl Remap {
pub fn new(path: &str) -> Remap {
Remap {
new_path: path.into(),
routes: HashSet::new(),
}
}
pub fn get(&mut self, path: &'static str) {
self.routes.insert(path);
}
}
impl BeforeMiddleware for Remap {
fn before(&self, req: &mut Request) -> IronResult<()> {
// TODO: do we really need to clone?
let original_url = req.url.clone().into_generic_url();
if self.routes.contains(original_url.path()) {
let mut changed_url = original_url;
changed_url.set_path(&self.new_path);
let changed_url = Url::from_generic_url(changed_url).expect("Unable to rebuild URL");
req.url = changed_url;
}
Ok(())
}
} main.rs mod remap;
use remap::Remap;
fn main() {
let mut mount = Mount::new();
mount.mount("/", Static::new(&root));
// Routes that are handled client-side
let mut remap = Remap::new("/");
remap.get("/about");
let mut remapped = Chain::new(mount);
remapped.link_before(remap);
info!("Starting the server on {}:{}", address, port);
Iron::new(remapped).http((&*address, port)).expect("Unable to start server");
} To be more complete, it should use the same underlying glob and route recognizer libraries as Iron to allow for the syntax to match. |
You can write a handler which tries two handlers and returns the first one that doesn't 404. |
And here's another solution, a year later struct Fallback;
impl AroundMiddleware for Fallback {
fn around(self, handler: Box<Handler>) -> Box<Handler> {
Box::new(FallbackHandler(handler))
}
}
struct FallbackHandler(Box<Handler>);
impl Handler for FallbackHandler {
fn handle(&self, req: &mut Request) -> IronResult<Response> {
let resp = self.0.handle(req);
match resp {
Err(err) => {
match err.response.status {
Some(status::NotFound) => {
let file = File::open("/tmp/example").unwrap();
Ok(Response::with((status::Ok, file)))
}
_ => Err(err),
}
}
other => other
}
}
} |
maybe it's worth to create middleware's or alike repository under /iron organization to stock these treasures? |
Hi,
I have several web apps where I have a chain where I first try to serve a static file, and if it doesn't exist, fallback to another handler. What's the recommended way to use such a fallback mechanism with staticfile? Right now, i defined my own custom handler that implements this cascading by delegating to static and catching 404, but I was wondering whether this is something that can be done without a custom handler; is this something that 'static' could implement? (i.e. a constructor that takes a path and a handler to call when the file isn't on the filesystem?
thanks,
Remko
The text was updated successfully, but these errors were encountered: