2006 年 8 月 31 日 23 時 57 分

本体としてのフォームの送信


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


[写真]


昨日は、URL の一部としてフォームを送信する例を見た。
これは、form 要素の action 属性が GET であったため、
HTTP の GET メソッドによって処理が行われたからである。

GET は Web サーバのデータを「取得」するのが目的であり、
フォームの送信によって登録や更新は発生しない。
つまり、これは「検索系」で利用されるメソッドである。

フォームの送信には、POST メソッドを使う方法もある。
POST の場合、Web サーバにデータを送信すると、
Web サーバで登録や更新作業が発生すると考えられる。
つまり、これは「更新系」で利用されるメソッドである。

では、POST によるフォームの送信を見てみよう。
今日の例は、mixi 日記のコメント入力フォームにしよう。

mixi の日記には「コメントを書く」というフォームがあり、
閲覧者が自由にコメントを投稿することができる。
以下の俺の日記のページをサンプルとしてみる。

http://mixi.jp/view_diary.pl?id=208404564&owner_id=2300658

まず、昨日と同じようにこのフォームを形成している、
HTML の断片を抜き出してみよう。

    <form action="add_comment.pl?diary_id=208404564" method=post>
    <input type="hidden" name="owner_id" value="2300658">
    <textarea name="comment_body" rows="5" cols="40" ></textarea>
    <input type="submit" value=" 確認画面 ">
    </form>

form 要素の method 属性が「POST」となっている。
送信先は「add_comment.pl?diary_id=208404564」だ。
この URL にはクエリ文字列が含まれている。

GET による送信の場合、フォームの内容によって、
クエリ文字列が自動的に生成されて追加されたが、
POST による送信の場合、URL には何も追加されない。

クエリ文字列は URL の書式の一部として規定されており、
パラメータを追加してもそれは URL として問題はない。
そのため、作成者は自由な URL を指定することができる。

この例の場合、GET によるフォームの符号化に似せており、
名前「diary_id」、値「208404564」の項目が、
GET でフォーム送信された場合と同等の設計にしてある。
URL の解析を単純化できるので、この手法は良く使われる。

さて、form 要素内には、新しい入力項目要素がある。
type="hidden" の input 要素は、隠し項目であり、
常に指定された名前と値の組み合わせを保持する。
この項目は画面に表示されないので、利用者には見えないが、
フォームを送信する際には、名前と値が送信される。

textarea 要素は、複数行用のテキストボックスだ。
rows 属性と cols 属性で行数と列数が指定できるが、
これは表示上の問題であり、実際には長い文が入力可能だ。
この入力項目も、名前と値を持つ。

では、実際に送信してみよう。
コメント用の複数行項目に、以下のように 2 行入力し、
「 確認画面 」ボタンを押して Fiddler で解析する。

    コメント
    二行目

フォームを送信したときの通信を写真に示しておく。
(Cookie ヘッダは、セキュリティの都合で改変している)

以下に、POST による通信の、主要な部分を抜粋する。
完全なリクエストについては、写真を参考にしてほしい。

========================================
POST /add_comment.pl?diary_id=208404564 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 84

owner_id=2300658&comment_body=%A5%B3%A5%E1%A5%F3%A5%C8%0D%0A%C6%F3%B9%D4%CC%DC%0D%0A
========================================

GET の時と比較して違う点は、
リクエストを送信する URL には変更が加えられないこと、
そして、リクエスト行とヘッダだけではなく、
Web サーバの返信の時に見たような本体が存在すること。
そして、Content-??? のヘッダが追加されたことである。

フォームの符号化自体は、GET の時と同じだ。
mixi は、文字エンコーディングに euc-jp を使うので、
フォームの内容も、euc-jp で符号化されている。
「%A5%B3%A5%E1%A5%F3%A5%C8」は「コメント」だ。
「%0D%0A」は、制御文字 CR と LF で改行である。
改行は、必ず CR-LF の組み合わせとなる。

POST では、フォームデータは、URL の一部ではなく、
「本体」としてヘッダ行の後に追加する形で送信される。
ヘッダ行は CR-LF だけのの空行で終端するので、
本体は、1 つ空行がある後に続けられる。
この本体のことを、メッセージボディとも呼ぶ。

ユーザエージェントが扱う URL には、
一般的に長さの制約があるため、
GET による送信ではそれほど多くの内容を扱えないが、
POST では URL の長さの制約を受けずに、
大きいデータを送信することが可能となるのだ。

本体を送る場合は、本体の情報を表すエンティティヘッダを
ヘッダ行に追加する必要がある。
POST の場合に必要なのは、本体の MIME タイプを示す、
「Content-Type」ヘッダと、本体のバイト数を示す、
「Content-Length」パラメータの 2 つである。

Content-Type は、本体の内容がどのようなものかを示す。
一般的なフォームの送信の際に利用される符号化は、
「application/x-www-form-urlencoded」という
MIME タイプとして規定されている。
Web サーバは、このヘッダを見て内容を識別するのだ。

本来 x- が付くのは実験的、独自という意味なのだが、
事実上、公式の MIME タイプと言っても過言ではない。
HTML や HTTP の仕様書にも明示されている上、
既に普及しているので、正式名への移行が難しいのだろう。

そう言えば、shift-jis も、x-sjis から移行するのに
結構時間が掛かったような気もするな。

POST によるフォームの送信の場合、
form 要素の enctype 属性で、
符号化の方法を選ぶことができる。
「application/x-www-form-urlencoded」以外に、
ファイルを送るための「multipart/form-data」がある。

さて、Content-Length では、
本文が占めるサイズを、「厳密にバイト数」で指定する。
今回は符号化を行っているが、符号化「後」のサイズだ。

Content-Length により、Web サーバは
これから送られるはずの本体のサイズを確認できるため、
何かしらの通信上の問題が生じ、
本体全体が Web サーバに到達しなかった場合に、
不十分な内容で登録等が行われる事を防ぐことができる。

POST メソッドによる送信は、
Web サーバに対して更新処理を引き起こすことが多いため、
フォームを送信した後に表示(返却)されるページは、
Web サーバの処理結果の画面であることが多い。

Web ブラウザで POST 後の画面表示を再読み込みする場合、
フォームの送信を再度行うことになるが、
この場合、Web サーバに再度内容が送信されるので、
2 重処理が行われる可能性がある。

そのため、Web ブラウザによっては、
POST フォームの送信に関する警告を出すものも存在する。

このように、GET と POST ではその役割が異なり、
フォームの送信の方法も違うのである。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.