静的生成と動的生成, Webページをビルドするコストは最初の訪問者に支払ってもらいましょう(さらに続き)。
公開日 : 2007-06-26 17:59:21
追記(2007年6月29日):
一連のエントリーで作成したものを取りまとめて公開しました。
何でこんなことやってんだろ(笑)。
まぁこういう負荷軽減のためのあれこれって結構楽しいわけです。動けばえーやん、から一歩進むための色んなコツみたいなものがあって、昔非力なMac、速度の出ないスクリプト言語(AppleScriptとかREALbasicとか)で工夫しながらやっていたことがこんなところで使えるとは...
関連エントリー
- 静的生成と動的生成, Webページをビルドするコストは最初の訪問者に支払ってもらいましょう。
- 静的生成と動的生成, Webページをビルドするコストは最初の訪問者に支払ってもらいましょう(続き)。
- 静的生成と動的生成, Webページをビルドするコストは最初の訪問者に支払ってもらいましょう(完結編!?)。
Movable Type10分間Cooking!(Part3)
今回はMovable TypeというよりHTTPヘッダを使ったクライアントキャッシュのコントロールが本題。ステータス404をちゃんと返さないと弾さんに怒られちゃうし。
前々回, 前回のはそのあたり全く考慮していないので、以下きちんと実装する。
- 最初のページへのリクエストがあった時(ページとファイルを生成する時)にクライアントに Last-Modified, Content-Length を返す(クライアントにきちんとキャッシュさせる)*
- ロボットからのアクセスの場合 HTTP_IF_MODIFIED_SINCE をチェック。entry->modified_on と比較してエントリーが更新されていなければ304 Not Modifiedを返す。ブラウザからのアクセスであればページをBuildしてファイルを構築する(その際ファイルのタイプスタンプを entry->modified_on にあわせる。
- エントリーが見つからなかった場合は404 Not Foundを返す。
*ETagは使わない。参考:14 rules for fast web pages (Skrentablog)
今回は理屈の説明はなし! (説明書くと15分かかるので10分間Cookingにならないし!)
チェックしているUserAgentはとりあえずGooglebotのみ。
touch しているのは、この方法だとファイルのタイムスタンプは常に modified_on よりも新しいものになってしまうので2回目のアクセスの時にHTTP_IF_MODIFIED_SINCEと時間があわなくなってしまうのでその対策。
テスト用ブログ : Junnama Online (Dynamic)
mtview.cgi
#!/usr/bin/perl -w
use strict;
use lib qw (/path/to/mt/lib/);
use lib qw (/path/to/mt/extlib/);
use MT;
use MT::Blog;
use MT::Entry;
use MT::Builder;
use MT::Template;
use MT::TemplateMap;
use MT::Template::Context;
use MT::Permalink;
use HTTP::Date;
my $mt = MT->new(Config => '/path/to/mt/mt-config.cgi');
my $base_url = 'http://junnama.alfasado.net';
my $base_pth = '/path/to/htdocs';
my $blog_id = 3;
my $request = $ENV{"REDIRECT_URL"};
my $url = $base_url.$request;
my $permalink = MT::Permalink->load({permalink => $url});
if (defined $permalink) {
my $modified_on = $permalink->modified_on;
my $yymmdd = substr($modified_on, 0, 8);
my $hhmmss = substr($modified_on, 8, 8);
my $yymmddhhmm = substr($modified_on, 0, 12);
my $ss = substr($modified_on, 12, 2);
$modified_on = $yymmdd.'T'.$hhmmss.'Z';
my $touch = 'touch -t '.$yymmddhhmm.'.'.$ss.' ';
$modified_on = &str2time($modified_on);
my $http_if_mod = $ENV{'HTTP_IF_MODIFIED_SINCE'};
$http_if_mod = &str2time($http_if_mod);
my $ua = $ENV{'HTTP_USER_AGENT'};
if ($ua =~ /Googlebot/i) {
if ($http_if_mod && ($http_if_mod >= $modified_on)) {
print "Status: 304 Not Modified¥n";
print "Last-Modified: $modified_on¥n¥n";
exit;
}
}
my $entry = MT::Entry->load({id => $permalink->id});
if (defined $entry) {
my $tmap = MT::TemplateMap->load(
{ blog_id => $blog_id,
archive_type => 'Individual',
is_preferred => 1
},);
my $template = MT::Template->load({id => $tmap->template_id});
my $page_tmpl = $template->text;
my $blog = MT::Blog->load({ id => $blog_id });
my $ctx = MT::Template::Context->new;
$ctx->stash('entry', $entry);
$ctx->stash('blog', $blog);
$ctx->stash('blog_id', $blog_id);
my $build = MT::Builder->new;
my $tokens = $build->compile($ctx, $page_tmpl);
my $html = $build->build($ctx, $tokens);
if ($html) {
$modified_on = &time2str($modified_on);
my $len = length($html);
print "Status: 200 OK¥n";
print "Last-Modified: $modified_on¥n";
print "Content-Length: $len¥n";
print "Content-Type: text/html¥n¥n";
print $html;
my $buildfile = $base_pth.$request;
$touch .= $buildfile;
open (OUT,">$buildfile");
print OUT $html;
close(OUT);
my $res = system($touch);
exit;
}
}
}
print "Status: 404 Not Found¥n";
print "content-type: text/html¥n¥n";
print "404 Not Found.";
さらにさらに続きはこちら↓。