Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Using shelf_static to serve static web pages through Dart is no problem:

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 fine 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 page if I request http://localhost:8080/ but explicitly asking for an existing page http://localhost:8080/home.html gives me Not Found.

Should I not even be trying to do this with shelf_static? If not, what would be the correct approach? Thanks!

like image 682
th65 Avatar asked Dec 06 '14 13:12

th65


People also ask

What is the difference between static and dynamic web pages?

Static pages can be interactive, but when it comes to functionality, dynamic pages definitely lead the way. Dynamic pages have boundless functionality—limited only by the complexity of the logic and language needed to build them, and the instructions needed to deliver content.

Are dynamic pages the only way to go?

For many website creators dynamic pages are the only way to go, and for good reason. Dynamic pages have the following advantages: Starting a business and building a brand online requires continually updated content. You need to stay current with trends, updates and changes within your business, as well as within your industry.

What type of website is a good candidate for static content?

A good candidate for a static site is a resume website. This is a type of site with set content for each page, and doesn't require many changes to individual pages, or real-time updates based on user behavior.

What languages are used to write static web pages?

It is written in languages such as HTML, JavaScript, CSS, etc. For static web pages when a server receives a request for a web page, then the server sends the response to the client without doing any additional process.


3 Answers

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

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}');
});
like image 81
Danny Kirchmeier Avatar answered Oct 16 '22 09:10

Danny Kirchmeier


The reason is that the shelf_route methods like get must fully match the path. With static files you don't want exact matches as the remainder of the path tells you the path to the file.

For this you need to use the add method and set exactMatch: false as currently the methods like get, post etc don't expose exactMatch.

The following 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've added a higher level framework called mojito that is a thin glue layer on many of the shelf components that makes this a little easier.

It's still kinda newish and poorly documented but in case you're 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 behind the scenes but also supports invoking pub serve in development mode which is very handy for stuff like polymer

like image 6
Anders Avatar answered Oct 16 '22 08:10

Anders


A fallbackHandler can be specified for the Router. It appears that using the static handler here solves the problem.

Router routes = new Router(fallbackHandler: staticHandler)
  ..get('/item/{itemid}', handler.doItem);
like image 2
th65 Avatar answered Oct 16 '22 10:10

th65