Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??
Preamble

In the first two parts of this serise of articles ("meet joe plack" and "serving static content with plack") on PSGI/Plack I introduced the concept of PSGI and provided some simple patterns to wet your appetite for it. Now in this 3rd part, I am going to introduce some more concepts and show how to begin using Plack to serve dynamic content.

Plack Builder

In part two, I used the module Plack::Builder to 'mount', various paths and bind them to apps based on Plack::App::File in order to serve up static content.

fragment of action.psgi ----------------------- my $app = builder { mount "/images" => $images; mount "/css" => $css; mount "/js" => $js; mount "/favicon.ico" => $ico; mount "/" => $htdocs; };

This is all well and good, and nicely implements a powerful static content server in PSGI.

Plack::Middleware

In order to make this more useful and to generate dynamic content, you will need to become familiar with the concept of Plack Middleware. In a nutshell, Plack Middleware components take a standard PSGI input, do some processing and then give a standard PSGI output, and thus Middleware components can be layered or stacked in a manner emulating Ruby's Rack system.

use Plack::Builder; use Plack::App::File; my $css = Plack::App::File->new(root => "/var/www/css"); my $js = Plack::App::File->new(root => "/var/www/js"); my $images = Plack::App::File->new(root => "/var/www/images"); my $ico = Plack::App::File->new(root => "/var/www"); my $action = sub { ($sec,$min,$hour,$mday,$mon, $year,$wday,$yday,$isdst) = localtime(time); return [200, [ 'Content-Type' => 'text/html' ], [ "<html> <head> <title>Plack Clock</title> </head> <body> <p>the time is $hour:$min:$sec</p> </body> </html>" ] ]; }; my $app = builder { mount "/images" => $images; mount "/css" => $css; mount "/js" => $js; mount "/favicon.ico" => $ico; mount "/" => builder { enable 'ContentLength'; $action; } };

So what's going on here then? Well first of all, we have now added a new sub called "action", which returns a basic html skeleton displaying the current time. Also, we have now mounted "/" to another instance of builder, which enables the Plack Middleware component called ContentLength (Plack::Middleware::ContentLength). This component takes the PSGI output of $action, calculates it's length and sets the appropriate response header.

Setup like this, all requests which don't start with "/images", "/css", "/js", of "/favicon.ico", will be routed to the $action sub, and will result in the browser showing the same page with the current time on it.

More Middleware

There are many middleware components available, and it is beyond the scope of this tut to go into them and describe them all so I am just going to show you a couple more and make some notes about layering them correctly before I sign off.

mount "/" => builder { enable 'ContentLength'; enable 'Debug', panels => [ qw(Memory Timer) ]; enable 'Session' store => 'File'; $action; }

We have now added 2 more Middleware components to the stack; Debug which adds a nifty collapsable panel to the right hand side of the browser display, and Session which of course gives access to a neat and secure session management system. (More about that later)

You may notice that the two new components have extra arguments compared to the ContentLength component. These extra arguments are passed to the Middleware component and modify it's behaviour. In this case we are telling Session to use the non-volatile file storage method of holding it's data, and we are telling the Debug component that we want to see two panels in it's display; Memory usage and a performance Timer

Stacking order

It's important to think about the logical order of the stack as you are building it. For instance, we put ContentLength at the top because we want the ContentLength component to be the LAST component to be run prior to output. This is so that the Content-Length header is correct. If we were to enable it in the wrong position, and a later component was to modify the length of the document, the header would be incorrect and may cause rendering errors on some browsers.

don't do this; wrong -------------------- mount "/" => builder { enable 'Debug', panels => [ qw(Memory Timer) ]; enable 'ContentLength'; enable 'Session' store => 'File'; $action; }

Now because we changed the order, the ContentLength is going to be calculated before the Debug Panel is added to the output, which may result in the debug panel not being visible at all.

Ok that's all for now folks, In the next article I am going to start looking in more depth at the actual content generation phase and in using any values generated by the Middleware in your app.

Have a good one!


In reply to Serving Dynamic Content with Plack by Logicus

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (6)
As of 2024-04-23 13:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found