How to serve both dynamic and static pages using Dart and shelf?

Using shelf_static to serve static web pages via Dart does not cause problems:

 var staticHandler = createStaticHandler(staticPath, defaultDocument:'home.html'); io.serve(staticHandler, 'localhost', port).then((server) { print('Serving at http://${server.address.host}:${server.port}'); }); 

and I can use shelf_route perfectly for dynamic web pages:

 Router routes = new Router() ..get('/item/{itemid}', handler.doItem); var handler = const shelf.Pipeline() .addHandler(routes.handler); io.serve(handler, 'localhost', port).then((server) { print('Serving at http://${server.address.host}:${server.port}'); }); 

But I'm struggling with adding a static handler to the dynamic version. Things I've tried include:

 Router routes = new Router() ..get('/item/{itemid}', handler.doItem) ..get('/', staticHandler); 

or...

  ..get('/.*', staticHandler); 

or...

  ..get('/{any}', staticHandler); 

All of which give me the specified default home.html , if I request http://localhost:8080/ , but explicitly requesting the existing page http://localhost:8080/home.html , it gives me not found.

Should I even try to do this with shelf_static ? If not, what will be the right approach? Thanks!

+8
dart dart-shelf
source share
3 answers

You can use Cascade . It creates a chain of handlers, moving on to the next, if the previous one gives a 404 or 405 answer.

 var staticHandler = createStaticHandler(staticPath, defaultDocument:'home.html'); var routes = new Router() ..get('/item/{itemid}', handleItem); var handler = new Cascade() .add(staticHandler) .add(routes.hander) .handler; io.serve(handler, 'localhost', port).then((server) { print('Serving at http://${server.address.host}:${server.port}'); }); 
+9
source share

The reason is that shelf_route methods such as get must be fully consistent with the path. With static files, you don't need exact matches, as the rest of the path tells you the file path.

To do this, you need to use the add method and set exactMatch: false , as currently methods like get , post , etc. Do not set exactMatch .

Next works

 void main(List<String> args) { Logger.root.onRecord.listen(print); var staticHandler = createStaticHandler('../static', defaultDocument:'home.html'); final root = router() ..get('/item/{itemid}', (Request request) => 'handling the item') ..add('/', ['GET'], staticHandler, exactMatch: false); printRoutes(root); io.serve(root.handler, InternetAddress.ANY_IP_V6, 9999); } 

FYI I added a higher level structure called mojito , which is a thin layer of glue on many components of the shelf, which makes this a little easier.

This is still curious and poorly documented, but in case you are interested, you can do the following

 void main(List<String> args) { Logger.root.onRecord.listen(print); final app = mojito.init(); app.router ..get('/item/{itemid}', (String itemid) => 'handling the item $itemid') ..addStaticAssetHandler('/', fileSystemPath: '../static', defaultDocument:'home.html'); app.start(); } 

addStaticAssetHandler calls createStaticHandler backstage, but also supports pub invocation in design mode, which is very convenient for things like polymer

+6
source share

A fallbackHandler can be set for a Router . It seems like using a static handler here solves the problem.

 Router routes = new Router(fallbackHandler: staticHandler) ..get('/item/{itemid}', handler.doItem); 
+2
source share

All Articles