1.リクエストヘッダとレスポンスヘッダ
インターネット上のサービスのほとんどはHTTPというプロトコルを利用しています。この仕様を抑えておけば、CGIプログラムの理解もより深まると思います。
HTTPプロトコルの概要
ウェブブラウザとウェブサーバは、『HTTP』というプロトコルを通じてメッセージの交換を行います。HTTPは、HTMLやテキストファイル、画像などのリソースをクライアントに送信するためのプロトコルとして開発されました。メッセージにはASCII コードを使用しているので、リソースに特殊文字や、日本語のような複数バイトの文字コードが含まれている場合は、『URL エンコード』と呼ばれる加工が施されてから送信されます。
HTTPのメッセージには、クライアント側が送信するリクエストヘッダ(request header)と、サーバ側が送信するレスポンスヘッダ(response header)の2種類があります。リクエストヘッダに関してはウェブサーバが処理するのでCGIの出番はありませんが、レスポンスヘッダはCGIで出力することができます。
CGIからレスポンスヘッダを出力し、ブラウザにページを表示させることはとても簡単です。
HTMLを出力する単純なプログラム
#!/user/bin/perl # レスポンスヘッダの出力 print "Content-type: text/html", "\n\n"; # HTMLの出力 print "<HTML>\n"; print "<BODY>\n"; print "ようこそCGIの世界へ!<BR>\n"; print "</BODY>\n"; print "</HTML>\n";
上記プログラムは、レスポンスヘッダを最初に出力し、次にHTMLを出力しているだけです。レスポンスヘッダにはさまざまな種類がありますが、ページを表示させるだけでしたら、Content-Typeを出力するだけで済みます。
ウェブブラウザとウェブサーバ間の通信
それでは、クライアントのブラウザからリクエストが送られてきたあと、ウェブサーバがレスポンスヘッダを返すまでの流れをざっと追っていきましょう。
- クライアントからサーバへリクエストが送信されます。
- クライアントからリクエストされたアドレスが CGIプログラムを指していれば、サーバはファイルの内容を表示する代わりにプログラムを実行させます。
- プログラムは必要な処理を行った後、リソースの内容やURLをウェブサーバに返します。
- プログラムの出力はウェブサーバの『標準出力』(STDOUT)に送られ、そこで正式なフォーマットに作り直されてから、最終的にクライアント側に送信されます。
用語
- HTTP
- (Hypertext Transfer Protocol)
TCP上で動作するプロトコル。サーバとクライアントとの間でデータをやりとりるための伝送機構。Webサーバとクライアントがデータを送受信するのに使われるプロトコル。HTML文書や、文書に関連付けられている画像、音声、動画などのファイルを、表現形式などの情報を含めてやり取りできる。SMTP、NNTP、FTPプロトコルなどの一般的なプロトコルとしても使用されます。 - URL エンコード
- 複数バイトの文字コードなどを URL として利用できるようにエンコードすることを意味します。
- 標準出力
- プロセスの処理結果を出力するための機構。デフォルトはディスプレイなどの画面デバイスがオープンされますが、他のプロセスやファイルに切り替えることもできます。
HTTPヘッダをTELNETから見てみよう
ウェブブラウザがHTMLや画像をリクエストするときは、HTTPヘッダのGETメソッドを使って、対象となるファイルを指定しています。
GET /test.html HTTP/1.0
上記では、「/test.html」ファイルの要求と、通信プロトコルHTTP/1.0を使うことを指定しています。
実際にブラウザがウェブサーバにリクエストしているのを見ることは難しいですが、ブラウザを使わずに直接ウェブサーバにリクエストを行い、それに対してウェブサーバがどう答えるかを見ることはできます。ウェブサーバに直接リクエストを送るには、telnetと呼ばれるソフトウエアを使用します。
ウインドウズでしたら、「ハイパーターミナル」というソフトウエアが標準でインストールされています。CGIを本格的に使うのでしたら、より高機能なTera Term Proというフリーソフトのご利用をオススメします。
Tera Term関連ホームページ
- UTF-8対応Tera Term
Tera Termの後継バージョンで、新たにSSH接続、UTF-8への対応が施されています。
- telnet
- 別のコンピュータに接続し、操作するためのソフトウエアの総称です。
それでは、telnetからウェブサーバに接続して、ファイルを指定して画面に表示させてみましょう。telnetを起動し、目的のサーバに接続、ログインしてください。コマンドラインが表示されたら、次のように入力していきます。太字が入力した行で、それ以外がウェブサーバが返した行になっています。
> telnet www.***.jp 80
Trying 123.123.123.98...
Connected to www.sampledomain.co.jp.
Escape character is '^]'.
GET /test.html HTTP/1.0
HTTP/1.1 200 OK
Date: Wed, 03 Jan 2001 17:22:53 GMT
Server: Apache/1.3.9 (Unix)
Connection: close
Content-Type: text/html
<html><body>
test.<br>
</body></html>
上記の例では、telnetコマンドで通信ポート80番を使って「www.***.jp」というドメインに接続しています。その後、GETメソッドを使って「test.html」ファイルを要求しています。ウェブサーバはGETメソッドの要求にしたがって、いくつかの必要なHTTPヘッダを出力し、空行の後に「test.html」ファイルの内容を出力しています。
HTTPヘッダを使ってダイナミックドキュメントを出力
CGIを使ってダイナミックドキュメントを出力するには、その内容の前にレスポンスヘッダを出力する必要があります。上記で行ったウェブサーバ接続へのテストで、ウェブサーバが出力したHTTPメッセージは、「HTTP/1.1 200 OK」から「Content-Type: text/html」の範囲です。完全なHTTPメッセージをプログラムで出力すると、次のようになります。
完全なHTTP メッセージを出力するプログラム
#!/user/local/bin/perl # 完全なレスポンスヘッダの出力 print "HTTP/1.1 200 OK\n"; print "Date: Wed, 03 Jan 2001 17:22:53 GMT\n"; print "Server: Apache/1.3.9 (Unix)\n"; print "Connection: close\n"; print "Content-Type: text/html", "\n\n"; # HTMLの出力 print "<HTML>\n"; print "<BODY>\n"; print "ようこそCGIの世界へ!<BR>\n"; print "</BODY>\n"; print "</HTML>\n";
ここで出力しているヘッダは、通信プロトコル、応答の日付と時間、サーバ名とバージョン、データの種類です。もちろん、先に紹介したサンプルプログラムのように、Content-Type と空行を出力するだけでも、ブラウザ側にダイナミックドキュメントを表示させることができます。
CGIプログラムからHTMLを出力したいときは、最低でも下記のようにContent-Typeと空行を出力します。あとはサーバが、足りないヘッダを追加して送ってくれます。
print "Content-Type: text/html", "\n\n";
HTTPは単純なプロトコルです。ヘッダ行は特別な順序にする必要がありませんし、ヘッダの終了は空行で見分けられます。上記では、「Content-Type: text/html」の後の空行でヘッダの終了を宣言しているので、その後に続く行でリソースの内容(HTMLなど)を出力するだけで終わりです。
HTMLからフォーム内容を送信するには、リクエストヘッダを理解しておいたほうがいいね。それから、CGI プログラムからHTMLや画像を出力する際は、レスポンスヘッダを出力する必要があるんだ。これを指定しないと、いつまでたってもブラウザに出力されることはないよ。
1.ブラウザが出力するリクエストメッセージ
ブラウザが送信するリクエストには、リソースの要求以外にも沢山の種類があります。リクエストはウェブサーバが処理するものなので、CGI側で意識するような場面はほとんどありませんが、そのいくつかは間接的に利用されています。その代表的なものがRefererやUser-Agentで、これらのヘッダは環境変数という機構に格納されて、CGIからアクセスすることが可能です。
リクエストヘッダ
ここでは、代表的なリクエストヘッダを紹介しておきましょう。
主なリクエストヘッダ一覧
フィールド名 | 説明 |
---|---|
If-Modified-Since | キャッシュの有効性の確認 このフィールドで指定した日付と、リソースの更新日を比較し、リソースのほうが新しい場合のみデータを取得できるように指示します。 |
Referer | 直前にリンクされていたURL情報 |
User-Agent | ブラウザの固有情報 |
Accept | 利用可能なアプリケーション・メディアタイプ 複数指定し、優先度を付けることが可能です。 |
Accept-Charset | 利用可能な文字セット |
Accept-Encoding | 利用可能なエンコーディング形式 |
Accept-Language | 利用可能な言語コード 複数指定し、優先度を付けることが可能です。 |
リクエスト・メソッド
リクエストはブラウザが出力するものですが、その内容は HTMLから指定することが可能です。リクエストメッセージ群には必ずメソッドと呼ばれるリクエスト行が含まれています。
メソッドとは、サーバにリクエストを指示するための命令です。HTTPで定義されているメソッドを紹介しましょう。
HTTP1.0で定義されているメソッド一覧
メソッド | 説明 |
---|---|
DELETE | URLで指定したリソースを削除 |
GET | URLで指定したリソースを取得 レスポンスのボディにはリソースのデータが含まれます。 |
HEAD | URLで指定したリソースについてのレスポンスヘッダのみ取得 |
POST | 指定したURLが示すサーバーのコマンドに対して、データを転送 リクエストのボディには転送するデータが含まれます。 |
PUT | 指定したURLが示すリソースに対して、データを転送して置き換え リクエストのボディには置き換えるデータが含まれます。 |
LINK |
(廃止されました) |
UNLINK |
(廃止されました) |
HTTP1.1で定義されているメソッド一覧
メソッド | 説明 |
---|---|
TRACE | サーバーやプロキシの動作を診断するための情報を返答 |
OPTIONS | 使用できるメソッドやオプションの一覧を取得 |
CONNECT | プロキシでのトンネリング接続を行う |
メソッドの中で実際によく利用されるのは GET メソッドと POST メソッドです。それ以外のメソッドは、セキュリティ上の問題などにより、実際に実装されているケースはほとんどありません。
GET メソッド
GET
メソッドはHTMLページや画像ファイルの取得に使用され、デフォルトのメソッドとなっています。例えばURLアドレスを指定されたり、リンクをクリックした場合には、GET
メソッドとしてウェブサーバに送信されます。
GET
の一般的な使い方はとても簡単です。アンカータグのhref属性の値に、クエリを追加するだけです。HTMLドキュメントでGET
を使うには、次のようにします。
<a href="/cgi-bin/query.cgi?post_data=1">...</a>
上記では、ファイル名の後にクエスチョン( ? )を挟んでGET
を指定しています。クエスチョン以降の「post_data=1」がクエリデータとして環境変数QUERY_STRING
に格納されます。ただし、渡されるデータがリミットを越えると、超えた分の値が切り捨てられます。
環境変数QUERY_STRING
を使用すれば、このクエリ情報にアクセスすることができます。CGIからQUERY_STRING
を利用する方法は「環境変数」の章で詳しく説明しますが、簡単な利用法を紹介しておきましょう。環境変数を参照するには、下記のように%ENV
変数を使って呼び出します。
# 環境変数 QUERY_STRING の値を $query_string に代入 $query_string = $ENV{'QUERY_STRING'};
GET
はリクエストヘッダのデフォルトです。リンクをクリックしたり、アドレスバーにURLを指定した場合もGETになるので、ほとんどのリクエストスヘッダが
GET によるリクエストになるといえるでしょう。
POST メソッド
HTMLページのフォームなどのデータは、POST
メソッドによって送信されるのが一般的です。
POST
は HTTPヘッダのボディ部でデータを送信します。各パラメータは標準入力で渡されます。データの長さ(バイト数)は環境変数CONTENT_LENGTH
に格納されています。
POST
の主な特徴は、クエリのサイズに制限がないことです。したがって、クライアントやサーバがデータを切り捨ててしまうことはありません。POST
によって送られたデータは、標準出力から取得することができます。
POST
は明示的に指定しないと使われません。HTMLのフォームタグでMETHOD属性にPOST
を指定します。
<FORM METHOD="POST"
action="test01.cgi">
2つのうちどちらかの方法でデータを送るかが決まると、データは指定された形式で送信されます。
2.CGI から出力できるレスポンスヘッダ
レスポンスヘッダは、ウェブサーバからブラウザに送信する HTTPメッセージです。基本的にはウェブサーバがレスポンスヘッダを送信するのですが、CGIプログラムからウェブサーバにレスポンスヘッダを出力することで、間接的にブラウザに返すことができます。その際、CGIプログラムは最低限「Content-type」を出力する必要があります。するとウェブサーバは、CGIプログラムが生成したヘッダを解析して、必要なヘッダを付け足してブラウザに送り返します。
レスポンス・ヘッダ
主なレスポンス・ヘッダ一覧
フィールド名 | 内容 |
---|---|
Server | ウェブサーバの名前とバージョン情報。 |
Date | 現在の日付(グリニッジ標準時) |
Last-Modified | リソースの更新日 |
Content-Length | 出力のバイト単位の長さ バイナリデータも含みます。 |
Content-Type | 出力のMIMEタイプ |
Expires | リソースの有効期限 この日付以降は無効です。キャッシュは破棄されます。 |
Location | リダイレクト URL 情報 Location で指定されたリソースが送信されます。 単独ヘッダとして出力されます。 |
Pragma | リソースのキャッシングを有効/無効にする 「Pragma: no-cache」と指定すると、リソースのキャッシュを無効にします。 |
Status | リクエストのステータス 単独ヘッダとして出力されます。 |
WWW-Authenticate | 認証データ。 認証に必要なユーザー名やパスワードなどの情報が含まれます。 |
Refresh | 指定されたドキュメントを再ロードする。 |
Set-Cookie | データをクライアント側に保存する。 |
レスポンスヘッダの構造
ウェブサーバからブラウザに送られる出力内容は、レスポンスヘッダとボディの2つです。HTTPヘッダはeメールで使用されている『MIME』に似たメッセージです。
CGIプログラムがこのメッセージの出力を忘れると、クライアント側のブラウザは正しくデータを受け取ることができず、サーバエラーのメッセージを表示します。ボディは、ヘッダで指定したフォーマットのデータタイプです。一般的なデータタイプはHTMLや画像です。
用語
- MIME
- MIME(Multipurpose Internet Mail Extensions)
MIMEは、元々は電子メールを通じて複数のデータタイプを送るために開発されたものです。MIMEタイプは、Web上のから送信されるデータタイプを識別するために使用されます。
Status : ステータスコード
ステータスコードは、リクエストの結果を知らせるための情報です。ウェブサーバは、ブラウザからのリクエストを正しく処理すると、次のようなステータスコードを返します。
HTTP/1.1 200 OK
ステータスコードはブラウザからのリクエスト結果を知らせるヘッダです。100番代から500番代までの状態コードが用意されています。CGIからこのヘッダを出力することはほとんどありませんが、CGIでエラーが発生したときなどは、ブラウザがこのステータスコードを表示します。
CGI エラーが発生した場合、ブラウザに次のようなメッセージが表示されることがあります。
Internal Server Error
The server encountered an internal error or
misconfiguration and was unable to complete your
request.
Please contact the server administrator.....
Additionally, a 404 Not Found error was encountered
while trying to use an ErrorDocument to handle the
request.
このときのページタイトルは「500 Internal Server Error」となっていて、ウェブサーバからステータスコード500番が返されたことがわかるようになっています。ステータスコード500番は「リクエストを実行中に予期しないエラーが発生した」というメッセージですので、CGIが原因ということが予測できます。
また、リクエストしたリソースへのアクセスが拒否された場合などは、ブラウザがエラー内容を表示し、そのページタイルが「403 Forbidden」となります。これで、CGIのエラーではなく、URLのタイプミスかファイルの属性の問題などにより、アクセスが拒否されたということが予測することができます。
Content-Type
Content-Type ヘッダは、CGI プログラムで最もよく使用する HTTPヘッダで、プログラムが出力する MIME タイプの情報をサーバやブラウザに伝えます。
書式は次のようになります。
Content-Type: media_type
media_type には、プログラムが出力する MIME タイプが入ります。MIMEタイプには一般タイプと特殊タイプの2タイプを明記します。
たとえば、HTML として出力したい場合は、一般タイプが text、特殊タイプが htmlになるので、次のように print を使って出力します。
print "Content-type: text/html", "\n\n";
主な MIME タイプは次の表のとおりです。
MIMEタイプ | 説明 |
---|---|
text/html | HTML文書 |
text/plain | テキストファイル |
image/gif | GIFファイル |
image/jpeg | JPEGファイル |
video/mpeg | MPEGファイル |
charset
Content-Type の行で、文字符号コードを指定することもできます。
Content-Type: text/html; charset=UTF-8
文字コードラベルの一覧
以下の一覧は、インターネットで使用可能な文字符号コードラベルの一部です。
文字コードラベル | ラベルのエリアス名 |
---|---|
ISO-2022-JP | csISO2022JP |
ISO-2022-JP-2 | csISO2022JP2 |
Shift_JIS | MS_Kanji / csShiftJIS |
UTF-8 | - |
Extended_UNIX_Code_Packed_Format_for_Japanese | csEUCPkdFmtJapanese / EUC-JP |
Character Set Recognition (Internet Explorer)
レスポンスヘッダのcharsetパラメータの代わりに、HTMLドキュメントのMETA要素で文字符号コード化を指定することもできます。
例えば、HTMLドキュメントの文字符号コード化がUTF-8の場合、以下のようなMETA宣言を記載します。
<META http-equiv="Content-Type" content="text/html; charset=utf-8">
Content-Length
HTTPを使って画像などのバイナリファイルを送信するときは、ファイルサイズの情報も一緒に送信するとよいでしょう。ファイルをブラウザに送信している途中で問題が発生しても、このヘッダ情報があればブラウザはファイルが完全に送信されていないことを知ることができます。また、このヘッダ情報を利用して、ダウンロードまでの時間をリアルタイムにユーザに伝えることもできます。
書式は次のようになります。
Content-length: number_of_bytes
CGI で画像を出力するには、次のような方法になるでしょう。
# -s オプションでファイルのバイト数を調べています $length = -s $file; print "Content-type: image/gif", "\n"; print "Content-length: $length", "\n\n";
Location
Locationヘッダを使うと、任意のリソースをブラウザに送るようにウェブサーバに命令することができます。Locationヘッダの引数には、URL 形式のパスを指定します。
書式は次のようになります。
Location: URL
URL には再読み込みを行うページの URL を指定します。
Locationヘッダの出力
#! /usr/local/bin/perl print "Location: /thanks.html", "\n\n";
ローカルのドキュメント以外にも、インターネット上のドキュメントを返すことができます。
print "Location: http://www.rfs.jp", "\n\n";
Refresh
このヘッダは、指定した時間が経過した後に任意の URL を再読み込みさせることができます。
Refresh: second; URL
second には再読み込みまでの待機時間を秒で指定し、URL には再読み込みを行うページの URLを指定します。
60秒後に「http://www.rfs.jp/」サイトを読み込ませるには、次のようにします。
print "Refresh: 60; http://www.rfs.jp/", "\n\n";
キャッシュの無効:Expiresヘッダ/Pragmaヘッダ
多くのブラウザは読み込んだHTMLファイルをキャッシュすることができます。キャッシュを無効にするには、Expires
ヘッダまたは Pragma ヘッダを使います。
Pragma で指定する場合は「no-cashe」オプションを使います。
print "Content-type: text/html", "\n"; print "Pragma: no-cache", "\n\n";
Expires を使う場合は古い日付を指定します。
print "Content-type: text/html", "\n"; print "Expires: Wednesday, 03-Jan-01 17:22:53 GMT", "\n\n";
※いくつかのブラウザはこれらの指定を無視します。
HTTPヘッダ関連サイト
- HTTP-Hypertext Transfer Protocol Overview [英]
HTTPに関する仕様書 - Common Gateway Interface RFC Project [英]
CGI に関する仕様書 - CGI/1.1 Revision 03 [英]
- HTTPを定義している技術書(RFC)
RFC文書の日本語翻訳です。すっごく役立つよ。 - Client
Side State - HTTP Cookies
クッキーに関するネットスケープの仕様書 - インターネット・プロトコルの世界
- インターネット興隆の立役者「HTTP~前編」
- インターネット興隆の立役者「HTTP~後編」
- 登録されているMIME タイプ一覧