取势 明道 优术

作者为 扶 凯 发表

因为自己喜欢这个简单实用的 Web 框架(半小时学会…呵),为了自己学习所以译了一下这个文章.放到网上只是希望有相同爱好的人,可以不用重复我这个过程也帮助到玩 Perl 的一些爱好者.另外,有什么建议可以直接写在下面,整个文件以 pod 的原版来译的.

 

名称

Dancer::Introduction – Dancer 的介绍

 


描述

Dancer 是一个 Perl 所写的开源的自由的 Web 应用的迷你框架,可以用于快速高性能的开发

 


安装 Dancer

要安装 Dancer 非常的容易,建议使用 cpanm 来安装

perl -MCPAN -e 'install Dancer'

我们非常感谢有 cpanminus(cpanm) 这个好用的东西,使用它,你不需要使用 CPAN.pm 的配置. 可以非常快速的运行.想使用这个来安装的话,只要在你的类 Unix 的系统中运行下面的命令.

wget -O - http://cpanmin.us | sudo perl - Dancer

(如果你没有 root 的帐户,cpanminus 会安装你的 Dancer 到 ~/perl5)

 


Dancer 的设置

我们的应用大多会使用 Dancer 的帮助脚本来创建一个 Web 应用,当然也可以不用.建议使用:

dancer -a MyApp

启动你的 Web 应用:

cd MyApp
bin/app.pl

在你使用 dancer 脚本生成的目录中有一个 bin 的目录,下面的 app.pl 是用来启动你的应用的.你可以看看 bin/app.pl --help 的输出相当帮助,可以用这些中的参数来设置端口之类的参数. 默认可以通过 3000 的端口见到你的应用的输出.

http://localhost:3000

 


Dancer 的用法

当你给 Dancer 写成一个简单文件时,这个文件就会变成 webapp 的网页应用.这时全部的内容会通过路由(routes)的字符描述来声明三个元素的列表.一个路由的声明由HTTP 的方法匹配的路径和一个代码块三部分组成.
strict 和 warnings 的程序也会由 Dancer 自动导入.

这三部分中的代码块,会通过路由的方法来执行并返回给客户端的内容.

路由是定义给 HTTP 的请求方法用的. Dancer 本身的模块会导出这些关键字来支持所有的请求方法.

下面的例子是一个路由的定义.这个路由是给 'get' 的方法定义的.所以只支持 GET 的 HTTP 请求.下面的意思是我们使用 HTTP 的 get.来尝试打开一个网页,然后 /hello 是有关路由的描述.指出会访问 /hello 的地址,最后面是一个代码块来表明当前用户访问这个 URL 时会发生什么.在例子中会返回提交的参数.这个是直接返回的,所以会默认渲染成页面.通常在处理器 handler 的子函数最后一行总是会让你在浏览器中渲染点什么.

    get '/hello/:name' => sub {
        # do something

        return "Hello ".param('name');
    };

 

HTTP 的方法

你可以在你的路由的处理中使用所标准的 HTTP 的方法.

GET 这个 GET 的方法取回一些信息 (当在这个 GET 的方法被定义时, Dancer 会自动的为 HEAD 方法做一个路由处理的定义. 要定义这个 GET 的操作,使用 get 的关键字. POST 这个 POST 的方法是用来在服务器上创建一些资源的. 要定义这个 POST 的动作,使用 post 的关键字. PUT 这个 PUT 的方法是用来更新已经存面的资源. 要定义这个 PUT 的动作,使用 put 的关键字. DELETE 这个 DELETE 的方法,是用来删除源服务器上的标识符中指出的内容. 要定义这个 DELETE 的动作,使用 del 的关键字.

你要定义一个路由来处理多个方法时.你可以指定使用 any . 下面的例子 就是用来定义同时支持 GET 和 POST 的方法的.

    any ['get', 'post'] => '/myaction' => sub {
        # code
    };

另外,下面的这个路由的方法处理所有的 HTTP 的方法:

    any '/myaction' => sub {
        # code
    };

 

路由的处理

路由所做的动作,其实就是写的那个代码块引中所声明的内容,它可以通过 'params' 关 键字来操作参数访问,参数会返回一个 hash 引用. 这个引用,包含了了路径和请求的参数.

有关更加详细的内容,你可以读 the Dancer::Request manpage 的文档.

 

路径名字匹配

一个路由匹配参包含一个和多个记号(通过 : 的前缀).每个记号,分别取得路径中匹配到的 内容成一个命名匹配.任何匹配到的内容,会存到名叫 param 的参数的 hash 引用中.

    get '/hello/:name' => sub {
        "Hey ".param('name').", welcome here!";
    };

这个记号也可以是可选的,如下:

    get '/hello/:name?' => sub {
        "Hello there " . param('name') || "whoever you are!";
    };

 

路径通配符

路由可以的路径中,也可以包含通配符(使用 "*"),每个通配符用匹配到的会返回一个数组 的引用,可以通过 splat 的关键字来切开访问.

    get '/download/*.*' => sub {
        my ($file, $ext) = splat;
        # do something with $file.$ext here
    };

 

正则表达式来匹配

在路由选择中,可以使用 Perl 的正则表达式.

你必须告诉 Dancer 是一个真实可用的正则表达式,必须使用 qr{} 来设置,如下:

    get qr{/hello/([\w]+)} => sub {
        my ($name) = splat;
        return "Hello $name";
    };

 

条件匹配

有路径选择时,我们可能想根据一定的条件,如 useragent 和主机名.

    get '/foo', {agent => 'Songbird (\d\.\d)[\d\/]*?'} => sub {
      'foo method for songbird'
    }

    get '/foo' => sub {
      'all browsers except songbird'
    }

 

PREFIX(前缀)

前缀是为各自的路由(route)处理所定义,象这个:

    prefix '/home';

在这,任何的路由的处理都会默认的处理 /home/*

    get '/page1' => sub {}; # will match '/home/page1'

你也可以设置成 undef 的值

    prefix '/'; # or: prefix undef;
    get '/page1' => sub {}; will match /page1

或者,你担心忘记设置这个,可以使用语法变量的这个参数来设置一个范围.

    prefix '/home' => sub {
      get '/page1' => sub {}; # will match '/home/page1'
    }; ## prefix reset to previous value on exit
    
    get '/page1' => sub {}; will match /page1

 


跳过动作

一个动作可以在 Dancer 的处理中跳过,并不需要服务器上来做.只要告诉 Dancer 的来找下一个能 匹配的路由.

这只需要使用 pass 的关键字就行,象接下来的例子

    get '/say/:word' => sub {
        return pass if (params->{word} =~ /^\d+$/);
        "I say a word: ".params->{word};
    };

    get '/say/:number' => sub {
        "I say a number: ".params->{number};
    };

 

ERROR 页

当要用出错页时,动作也会自动输出 200 的响应码.Dancer 会首先检查 public 目录 是否有这个网页(例: 500.html or 404.html).

如果这个文件存在,就会给出这个出错,不然会输出默认的出错网页.

 

执行出错

当在路由的处理执行过程中出错时.Dancer 会输出出错的网页,并显示 500 的出错代码.

这可能显示二种内容,一种是这个出错的网页,另一个是全局的出错网页.

这个可以由 show_errors 来设置.

你也可以改变路由处理中的全部的警告,通过 warnings 设置.

 


过滤器

 

前过滤器

前过滤器是在每个请求之前进行的,你可以修改请求进来的内容和响应. 你可以通过 'var' 的关键字来很容易的设置变量在你的动作的块中使用.

    before sub {
        var note => 'Hi there';
        request->path_info('/foo/oversee')
    };

    get '/foo/*' => sub {
        my ($match) = splat; # 'oversee';
        vars->{note}; # 'Hi there'
    };

其它的例子,这也能使用通过会话支持很容易的检查用户登陆.

    before sub {
        if (!session('user') && request->path_info !~ m{^/login}) {
            # Pass the original path requested along to the handler:
            var requested_path => request->path_info;
            request->path_info('/login');
        }
    };

这个 request 的关键子,会返回当前的 Dancer::Request 的对象.可以看 the Dancer::Request manpage 模块的文档.

 

后过滤

after 的过滤器是用来在响应的内容被创建之后.这个可以用来修复响应本身,然后发送给用户.

这个过滤器取得响应的对象做为第一个参数:

    after sub {
        my $response = shift;
        $response->{content} = 'after filter got here!';
    };

 

前模板过滤器

before_template 这个会钩住调用它的模板的程序这可以通过 hash 来修改内容.

    before_template sub {
        my $tokens = shift;
        $tokens->{foo} = 'bar';
    }

这个 tokens 的哈希会通过模板来修改模板中变量的内容.这是一个非常好的设置全局变量 到你的模板中的机会.象用用户登陆的用户名.

 


配置和环境

配置 Dancer 的应用有好几种方法,最容易的方法(最直接的)是声明设置在你的程序上, dancer() 的方法之前.

其它可能的方法是,你可以写你的设置到 'appdir/config.yml',在这之前,你必须安装 YAML 的模块. 然后写成 YAML 的配置.

这是首选的最好的方法是,但也有一点不好,就是会影响其它的作者.

所以最好的方法是写一个全局的配置文件设置全局的内容到 config.yml.

    # appdir/config.yml
    logger: 'file'
    layout: 'main'

然后写各自的环境文件到你应用的目录象 appdir/environments. 这样,合适的环境配置会被自动的加载到你运行的环境中.如果不指定,默认是 'development' 开发环境.

注意,你可以很方便的修改环境,只要在命令行中加入 –environment 的参数.

典型的,你可以设置下面的值到你们开发的环境的配置文件中:

    # appdir/environments/development.yml
    log: 'debug'
    startup_info: 1
    show_errors:  1

生产环境就需要:

    # appdir/environments/production.yml
    log: 'warning'
    startup_info: 0
    show_errors:  0

 

load

你可以使用 load 的方法,来插入附加的路由到你的应用中:

    get '/go/:value', sub {
        # foo
    };

    load 'more_routes.pl';

    # then, in the file more_routes.pl:
    get '/yes', sub {
        'orly?';
    };

load 这个只是包装了 require,但这个中,你可以指定一个路由方法的文件列表. routes files:

    load 'login_routes.pl', 'session_routes.pl', 'misc_routes.pl';

 

访问配置数据

在 Dancer 的应用中,我们可以很容易的访问配置文件中的信息.只需要通过 config 的关键字.

    get '/appname' => sub {
        return "This is " . config->{appname};
    };

 


导入 syntax

如果你使用了复杂的文件层次.你需要为 Dancer 导入一些 syntax.

    package App;

    use Dancer;            # App may contain generic routes
    use App::User::Routes; # user-related routes

你只需要在 App/User/Routes.pm 中使用.

    use Dancer ':syntax';

    get '/user/view/:id' => sub {
        ...
    };

 


日志

如果想通过你的应用程序发送 log 信息.在当前的版本中,只能通过附加 logging 的模块.

下面就是在你的应用中加载日志.你首先要在你的配置文件中加入如下:

    logger: 'file'

你可以修改你日志显示的东西.

    log: 'debug'     # will log debug, warning and errors
    log: 'warning'   # will log warning and errors
    log: 'error'     # will log only errors

可以直接在你的 appdir/logs 中找到环境的日志文件.日志文件包含写入的时间, PID 的调用信息.

日志信息中可以有 debug, warning 和 error 的方法.

    debug "This is a debug message";

 


使用模板

 


视图

动作的内容的输出,可以使用模板技术;只需要在 view 中调就行了. 'appdir/views' 的目录放着视图的文件.

你也可以修改本地的目录,通过设置 'views'.下面的例子就是怎么设置 templates 的目录.

    set views => path(dirname(__FILE__), 'templates');

默认,我们是使用的内部的模板引擎(the Dancer::Template::Simple manpage),可能你更加想升级使用 Template::Toolkit.如果你想这样,你只需要设置一下就行了. the Dancer::Template::TemplateToolkit manpage. 你需要导入 Template 的模块到你的应用中.注意 Dancer 的配置中 Template::Toolkit 的引擎是使用的 <% %> 来做默认的块识别.不是 [% %] .当然,你也可能在配置文件中修改.

全部的视图必须是 '.tt' 的扩展名.你可能想修改这个特性.

当你在程序中需要调用模板显示时,只需调用 'template' 关键字.然后给一个视图名和一个 hash 的引用 到视图中就行了(注意在 request, session 和 route params 会自动的在 view ,named request,session 和 params 中访问).

    use Dancer;
    use Template;

    get '/hello/:name' => sub {
        template 'hello' => { number => 42 };
    };

如上,调用的 hello 的视图,在 appdir/views/hello.tt 的视图包含如下的内容.

   <html>
    <head></head>
    <body>
        <h1>Hello <% params.name %></h1>
        <p>Your lucky number is <% number %></p>
        <p>You are using <% request.user_agent %></p>
        <% IF session.user %>
            <p>You're logged in as <% session.user %></p>
        <% END %>
    </body>
   </html>

 

LAYOUTS(版面布局)

layout 是针对视图的.通过 'layouts' 来指定,内部视图的目录.必须包含 'content' 的名字. 这会取得动作的视图的内容放到这个中.所以可以给你的动作设置全局的版面. 当你调用 'template' 关键字时,会自动的给相关可用的符号拿到模板的布局中使用. 象标准的 session, request,和 params 的符号.这可以让你插入内容到 HTML .这些网页的标题,当前网页的 tags .

这个例子中的布局: views/layouts/main.tt:

    <html>
        <head><% page_title %></head>
        <body>
        <div id="header">
        ...
        </div>

        <div id="content">
        <% content %>
        </div>

        </body>
    </html>

这个布局可以象下面这样使用:

    use Dancer;
    set layout => 'main';

    get '/' => sub {
        template 'index' => { page_title => "Your website Homepage" };
    };

当然,如果 layout 是设置的,你也可以禁用这个动作,象下面:

    use Dancer;
    set layout => 'main';

    get '/nolayout' => sub {
        template 'some_ajax_view',
            { tokens_var => "42" },
            { layout => 0 };
    };

 


静态文件

 

静态目录

静态文件会被存在 ./public 的目录.你指定不同的目录只需要设置 'public' 的选项:

    set public => path(dirname(__FILE__), 'static');

注意这个 public 的目录名并不包含在 URL 中.一个文件 ./public/css/style.css 的路径是后面的 example.com/css/style.css.

 

路由处理中的静态文件

你可能想在路由的处理中输出静态文件.

    get '/download/*' => sub {
        my $params = shift;
        my ($file) = @{ $params->{splat} };

        send_file $file;
    };

如果你想发送 index 的网页:

    get '/' => sub {
        send_file '/index.html'
    };

 


设置

这是一个非常快的方法来修改你的应用中的参数.

只需要通过 set 的关键字来设置 key/value 的值对.

    set setting_name => 'setting_value';

更加有用的,设置可以写到 YAML 的配置文件中. 环境指定设置可以设置在环境的配置文件中.例如,你不想在生产环境中使用 auto_reload, 你也许想设置支持日志在你的开发环境中.你可以看看 cookboos 的实例.

the Dancer::Config manpage 有更多复杂详细的支持的设置.

 


序列化

当我们写 webservice 时,数据的序列化/反序列化 是常常做的.Dancer 可以通过 serializer 自动的处理这些.

当你设置了 serializer, 新的处理的任何路由中,只要响应的数据是非标量的.就会被序列化成字符.

下面是在路由处理的例子,会返回 hash 的引用.

    use Dancer;
    set serializer => 'JSON';

    get '/user/:id/' => sub {
        { foo => 42,
          number => 100234,
          list => [qw(one two three)],
        }
    };

只要数据是非标量和设置了序列化.它就会直接返回当前的值的序列化.

所以,如果是设置了 JSON 的序列化,这个返回的结果就会如下:

    {"number":100234,"foo":42,"list":["one","two","three"]}

当序列化可用时,会在你的系统中动态的加载 Perl 模块.

JSON

requires JSON

YAML

requires YAML

XML

requires the XML::Simple manpage

Mutable

这会自动的根据 Content-TypeAccept-type 来处理

 


实例

这是由 Dancer 创建的一个可用的 webapp:

    #!/usr/bin/perl

    # make this script a webapp
    use Dancer;

    # declare routes/actions
    get '/' => sub {
        "Hello World";
    };

    get '/hello/:name' => sub {
        "Hello ".param('name');
    };

    # run the webserver
    Dancer->dance;

 


AUTHORS

Dancer contributors – see AUTHORS file. 译者: 扶凯

 


NOTE

本文由个人根据 cpan 翻译,可能由于水平有限,译文质量望读者见谅,不屑一顾者请绕道远行,英文好的请直接看原著(最好也帮助翻译). — PerlChina 重建计划作品

备注
常用名词列表:
handler 处理器
routes   路由(路由后的工作由处理器来处理)
actions 动作

来了就留个评论吧! 5个评论



    wxlfhwxlfh wxlfh 2011年12月3日 的 01:38

    赞!支持一个。

    zhengsenlin 2013年05月30日 的 04:10

    支持,写到很好。

    Weijian Rao 2015年03月4日 的 12:56

    你好。
    我安装好Dancer模块后,并没有生成可执行的dancer文件,请问这个是自动生成在哪个目录下的呢?还是需要一些额外的操作?

      扶 凯 2015年03月5日 的 11:16

      我不使用这个了。我现在使用 Mojolicious