LoginSignup
4
1

More than 5 years have passed since last update.

[Perl] PSGI入門第二章 CGI::SessionをPSGIで無理やり使う

Last updated at Posted at 2017-02-11

この記事には問題があります。

こちらをお読みください。

本日のお題:CGI::SessionをPSGIで無理やり使う

こ## おさらい

背景

  1. 新しいウェブアプリケーションを書くにあたって
  2. PCGIを使うべきか Mojoliciousを使うべきか悩んだ
  3. 調べてみたらセッションに大きく違いがあった
  4. Plackのセッションの実装は非常に簡素1
  5. Mojoliciousのセッションはちょっと特殊2
  6. 中間が欲しいんだよね。ってかCGI::Sessionをそのまま移植したようなのが使いたい

やってみた。

結論から先に書くとこうなります。

Myapp.pl
use strict;
use warnings;
use Carp;

use Plack::App::Path::Router::PSGI;
use Path::Router;
use Plack::Request;

use CGI::Session;
my $session = CGI::Session->new( undef, undef, { Directory => './sessions' } ); # ダミーのセッション
my $sid = $session->param('CGISESSID') || undef;
$session->delete(); # ダミーはすぐ消す
$session = CGI::Session->new( undef, $sid, { Directory => './sessions' } ); # 本セッション
if ( $session->is_expired() ) { # 期限切れを消して再発行
    $session->delete();
    $session = CGI::Session->new( undef, undef, { Directory => './sessions' } );
}else{
    $session->expire('+1d');
}

my $router = Path::Router->new;
$router->add_route( '/' => target => \&root );
$router->add_route( '/env' => target => \&env );

# now create the Plack app
my $app = Plack::App::Path::Router::PSGI->new( router => $router );
$app->to_app();

sub root {
    my $env = shift;
    my $req = Plack::Request->new($env);
    my %param = %{ $req->body_parameters };
    if( exists $param{'action'} and $param{'action'} eq 'forget' ) {
        $session->param( 'str', '' );
    }elsif( exists $param{'str'} ){
        $session->param( 'str', $param{'str'} );
    }

    my $str = $session->param('str') || '';
    return response( $env, <<"END");
<html><body>
    <h1>セッション管理してみる</h1>
    <form method="POST" action="/" enctype="multipart/form-data">
        <input type="text" name="str" value="$str">
        <button type="submit" name="action" value="remember">記憶</button>
        <button type="submit" name="action" value="forget">消去</button>
    </form>
</body></html>
END
}

sub env {
    my $env = shift;
    my @str;
    while ( my ( $key, $value ) = each %$env ) {
        push @str, "$key = $value" unless ref $value;
    }
    return response( $env,
        join( "<br>\n", '<html><body><h1>環境変数一覧</h1>', sort(@str), '</body></html>')
    );
}

# サブルーチン
sub response {
    my $env = shift;
    my $body = shift || croak 'empty body!';
    my %ARG = @_ if @_;
    my $status = $ARG{'-status'} || 200;
    croak "unvalid status: $status" if $status !~ /^\d{3}$/s;
    my $mime = $ARG{'-MIME'} || 'text/html; charset=utf-8';
    my $headers = $ARG{'-headers'} || {};
    my $req = Plack::Request->new($env);
    my $res = $req->new_response($status);
    $res->content_type($mime);
    $res->header(
        'Set-Cookie' => $session->cookie,
        %$headers
    );
    $res->body($body);
    $res->finalize;
}

結論、Set-Cookieヘッダに$session->cookie渡すだけ3なんですよね。全然、過去の資産引き継げます。前回紹介した環境変数一覧がこっそり/envにルーティングされてる点も注目ですよ!
ね、簡単でしょう?あなたも始めよう!PSGI!

次章

宣伝

本記事は自前で有料WebサービスをPerlで書いてリリースするに辺り、つまづいた点や気づいたことを共有する目的で書き始めました。

worthmine-qiita.pngこちらのQRコードをスマホで読み取り、
興味を持った方はhttps://qrown.meまでぜひお立ち寄りください!



  1. Plack::Middleware::Sessionによると、expire()すら単なるdeleteでしかない。 

  2. GitHubに丁寧な日本語訳があります。 

  3. Plack::Responseにはcookiesメソッドがあるが、どちらかというと生cookie派の仕様で、セッション管理には向かない。 

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1