IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

Plack 代码和结构分析-PSGI Application Architecture[译]

扶凯 2015-02-26 22:29:04 累计浏览 1,604 次
本机暂存

PSGI Applications

PSGI spec 中定义了有关 PSGI 的应用相关的内容.

PSGI 应用是一个 Perl 代码块的引用. 它需要一个参数, 环境变量, 并返回一个包含着三个值的数组.

这三个值是 HTTP 的状态 status, 响应的 header, 和 body. 下面是一个简单的例子:

my$app= sub{
    my$env= shift;
    return[
        '200',
        [ 'Content-Type'=> 'text/plain'],
        [ "Hello World"], # or IO::Handle-like object
    ];
};

PSGI 环境变量的哈希

PSGI 环境变量的哈希是一个有很多键的哈希引用. 它主要是这些 (headers, body, etc), 都是从 HTTP::Request 解析并放到这个哈希中来给方便访问.

中间件

中间件会取得 PSGI 的应用, 并运行和传送 PSGI 的环境变量的哈希给它. 它在运行 PSGI 的应用之前, 如果有需要, 它可能会修改环境变量. 并且在运行完应用之后, 它也可能修改响应的内容.

Plack::Middleware

中间件是围绕在 PSGI 的应用上来封装的. 应用可以被一个或者多个中间件包围封装, 这样可以创建一层又一层就象洋葱 onion. 事件驱动和回调让中间件有着不同寻常的结构.

所有的中间件都继承 Plack::Middleware. 它是一个非常小的模块. 这个中间件模块只有 2 个很短的子函数  (注意 call() 和 prepare_app()这二个函数是由使用者来完成):

译注: 现在其实只有一个 wrap 函数了. 其中 to_app 现在是在 Plack::Component 模块中实现. to_app 是用于返回代码块.

subwrap {
    my($self, $app, @args) = @_;
    if(ref$self) {
        $self->{app} = $app;
    } else{
        $self= $self->new({ app => $app, @args});
    }
    return$self->to_app;
}
  
subto_app {
    my$self= shift;
    $self->prepare_app;
    returnsub{ $self->call(@_) };
}

这些函数是怎么样在一起工作的? 这些中间件的洋葱结构决定了, 可以这样构造:

my$app= MyWebApp->new->to_app;
$app= Plack::Middleware::A->wrap($app);
$app= Plack::Middleware::B->wrap($app);
$app= Plack::Middleware::C->wrap($app);

象下面这样写, 可能更加清楚和容易让你明白

my$app0= MyWebApp->new->to_app;           # $app0->($env) 运行 web app
$app1= Plack::Middleware::A->wrap($app0);  # $app1->($env) 调用 P::M::A->call() 这是 $app0->($env)
$app2= Plack::Middleware::B->wrap($app1);  # $app2->($env) 调用 P::M::B->call() 这是 $app1->($env)
$app3= Plack::Middleware::C->wrap($app2);  # $app3->($env) 调用 P::M::C->call() 这是 $app2->($env)
                                            # 当服务器收到一个请求时调用 $app3->($env)

当有新的事件发生时 - 例如, PSGI 的服务器收到一个新的请求 — 它传送这个事件给应用 app. 这个 app 是链式回调来运行每个. 这显然就是事件驱动编程的例子.

Plack::Component 和 Plack::App

Plack::Middleware 继承自 Plack::Component.所以中间件也是使用了 Plack::Component 中的东西.

Plack::Component 是用于创建 PSGI 应用的工具. 它也是很轻量一层的代码, 它主要是用于 Plack::App 名字空间的一些模块实现用的接口. Plack::App::File 是一个 Web 服务器, 用于实现指定目录的静态文件输出,Plack::App::URLMap 是用于给多个 url 指向不同的应用.  

但注意, 我们并不需要在我们的 PSGI 的应用中来指定来 use Plack::Component .  一个 PSGI 的应用只是一个代码块的引用. 这个 PSGI spec 没有讲 PSGI 的应用需要继承 Plack::Component.

我们使用 Plack::Component 提供的接口来在自己创建的应用中使用这些接口. 当我们见到 $app 时, 我们就可以使用这些行为, 这显然看起来就象中间件, 但从设计的角度来讲, 分离开来比较好.

不过这个东西不是在我们的应用中必须的, 它会增加我们的复杂性.

来源: <http://blog.kablamo.org/2014/04/11/read-plack-3/>

同分类推荐文章

  1. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. 百度账号系统国际化实践 (累计阅读 3,736)
  2. 级联多个应用 (累计阅读 3,608)
  3. 在你的应用中添加 JSONP 的支持 (累计阅读 3,097)
  4. 通过中间件来实现应用的认证 (累计阅读 2,601)
  5. 应用中的静态文件 (累计阅读 2,541)
  6. 使用 plackup (累计阅读 2,269)
  7. Plack 代码和结构分析一[译] (累计阅读 1,955)
  8. 使用 plackup 重新加载应用 (累计阅读 1,926)
  9. Plack 代码和结构分析-Plack::Builder[译] (累计阅读 1,900)
  10. Plack 代码和结构分析-plackup Architecture[译] (累计阅读 1,552)