概要
form
タグやfetch()
で、GET
やPOST
前提
- クライアントは主にブラウザ
リクエストとレスポンス
- リクエスト: クライアントからサーバへ送信
- レスポンス: リクエストを受けて、サーバからクライアントへ送信
ブラウザ
- レスポンス内容(HTMLやJavaScriptなど)を解析し、画面表示
- FireFoxでの詳細確認: F12 => ネットワーク => ファイルをクリック
ステートレスのプロトコル
- バラバラのリクエスト
- 状態の保存なし
- あるリクエストと別のリクエストの結びつきがない
- 誰でも自由にリクエストできてしまう
- 「この前リクエストしたオレオレです、送金よろしく」
セッションの維持
- 本来バラバラのリクエストを結びつけること
クライアントの識別をどうするか
- リクエストにセッション情報を付ける
- 例: ログイン済みユーザ固有の、秘密の文字列
リクエストの構成要素
- メソッド: パスに関して希望の動作種類
- パス: 特定のリソースを示す
/
から始まる文字(ドメイン名より後ろの部分)- 例:
https://example.com/path/to/index.html
の/path/to/index.html
- 例:
- バージョン:
HTTP/1.1
やHTTP/2
など
- ヘッダ:
ヘッダ名: 値
(複数可) - ボディ: 本文(メソッドによる)
パス、ヘッダ、ボディにセッション情報
レスポンスの構成要素
- バージョン
- ステータスコード: リクエストの成功・失敗などを示す数字
- ステータスメッセージ: ステータスコードの説明
- ヘッダ
- ボディ
ヘッダ、ボディにセッション情報
HTTPS
TLS利用の上でHTTPをすること
- HTTPそのものに備わった暗号化機能ではない
- 暗号化用の別のHTTPがあるのではない
- リクエスト先ポートは
443
(HTTPは80
) - ブラウザで、
https://
〜のURLで自動
リクエスト・レスポンスの内容すべてが暗号化
- 別の理由により、完全な匿名性・機密性はない
- 例: YouTubeを見ていることはバレるが、どの動画かはバレない
(注意) ドメイン名は中間者に別途把握される
ブラウザ <==> 中間者 <==> サーバ
- IPアドレス(送信元と送信先)はHTTPの範疇ではない
- => IPアドレスからドメイン名の逆引き可能(複数なら候補)
- TLS(公開鍵証明書)のやりとり(Server Name Indication) => ドメイン名
- DNS利用 => ドメイン名
メソッド
パスとの組み合わせに意味
- パス(が示すリソース)についてどうしたいか
- パスが同じでも、メソッドの違いでサーバの処理が異なる(実装による)
よく使うCRUDな4メソッドと調査メソッド
POST
: 生成(追加)GET
: 読取PUT
: 更新DELETE
: 削除
OPTIONS
: 対応しているメソッドを調査
それぞれの役割に沿ってサーバを実装し、リクエスト側もそれを期待する。
GET
メソッド: 見るだけ
リソースに変化なし
- => 安全なメソッド
- リクエストボディなし
GET
になる例
- アドレスバーにURL入力
<a href="URL">リンク</a>
やimg
タグなどform
タグとfetch()
で、GET
設定のとき
POST
メソッド: 追加
リソースに変化あり
- => 安全ではないメソッド
- リクエストボディあり
- 指定パスと新リソースのパスとが違う可能性
POST
時のパス例: /user- 新リソースのパス例: /user/1234
POST
になる例
form
タグとfetch()
で、POST
設定のとき
OPTIONS
メソッド: 対応メソッド調査
特にCORSのプリフライトで使う
- アドレスバーのドメインとは別のドメインへリクエストするとき (一部)
ブラウザ動作のポイント
form
タグか、fetch()
か- 画面遷移する、しない
GET
か、POST
か- リクエストボディなし、あり
画面遷移するか、しないか
- セキュリティにかかわる: クロスサイト・リクエストのとき
遷移する
=> 新しいドキュメント(ページ)に画面が変わる
a
タグのリンクをクリックform
タグで送信
- (ここでの対象外) アドレスバーにURL入力、ブックマークから開く
遷移しない
=> 現在のドキュメント内でレスポンスを利用する
img link iframe
タグなどで外部ファイルを取り込むfetch()
form
タグでGET
- クエリ文字列付きのパスになる
- 画面遷移: レスポンスで得たボディへ
<form action="パス" method="get">
<form action="https://example.com/path/to/resource" method="get">
<input type="text" name="key" value="value">
<input type="text" name="キー" value="バリュ">
</form>
=> /path/to/resource?key=value&キー=バリュ
クエリ文字列
- パスの
?
以降 キー=バリュ
の形式で、複数なら&
区切り
fetch()
でGET
- クエリ文字列も可
- 画面遷移なし: レスポンスボディをJavaScriptから利用
fetch(URL, init)
init
オブジェクト: 設定- 戻り:
Promise
const init = {
method: 'GET',
}
fetch('https://example.com/パス?キー=バリュ&key=value', init).then(
res => res.json() // レスポンスボディがJSONなら
).then(console.log).catch(console.error)
Content-Type
リクエストヘッダ
POST
などにおいて、リクエストボディの形式を指定する。
application/x-www-form-urlencoded
form
タグでキー=バリュ
形式をPOST
(パスのクエリ文字列とは別物)
application/json
fetch()
でJSONをPOST
multipart/form-data
- ファイルアップロード
form
タグでPOST
キー=バリュ
形式のボディを送信- 画面遷移: レスポンスで得たボディへ
<form action="パス" method="post">
<form action="https://example.com/パス" method="post">
<input type="text" name="key" value="value">
<input type="text" name="キー" value="バリュ">
</form>
- ヘッダ自動:
Content-Type: application/x-www-form-urlencoded
fetch()
でPOST
- 画面遷移なし: レスポンスボディをJavaScriptから利用
JSONなボディを送信
JSON.stringify()
でbody
に入れるContent-Type: application/json
const init = {
method: 'POST',
body: JSON.stringify({キー: 'バリュ', array: [1, 2]}),
headers: {'Content-Type': 'application/json'},
}
fetch('https://example.com/パス', init).then(
res => res.json()
).then(console.log).catch(console.error)
キー=バリューのボディを送信
Content-Type: application/x-www-form-urlencoded
URLSearchParams
クラスでbodyに入れる
init.headers = {'Content-Type': 'application/x-www-form-urlencoded'}
init.body = new URLSearchParams({key: 'value', キー: 'バリュ'})