内容
ネットワークが作成された夢は、私たちが情報を共有し、通信する共通の情報空間です。 その普遍性は不可欠な部分です。ハイパーテキストリンクは、個人情報、ローカル情報、グローバル情報、下書き、検証済みテキストなど、どこにでも導くことができます。
Tim Bernes-Lee、World Wide Web:非常に短い個人史プロトコル
ブラウザーのアドレスバーにeloquentjavascript.net/17_http.htmlと入力すると、ブラウザーは最初にeloquentjavascript.netという名前に関連付けられているサーバーアドレスを認識し、HTTPのデフォルトポートであるポート80でTCP接続を開こうとします。 サーバーが存在し、接続を受け入れる場合、ブラウザは次のようなものを送信します。
GET /17_http.html HTTP / 1.1
ホスト:eloquentjavascript.net
ユーザーエージェント:ブラウザー名
サーバーは同じ接続を介して応答します。
HTTP / 1.1 200 OK
コンテンツの長さ:65585
コンテンツタイプ:テキスト/ html
最終変更日:2014年4月9日水曜日10:48:09 GMT
<!doctype html>
...ドキュメントの残りの部分
ブラウザは、空の行の後の回答の後に来る部分を取得し、HTMLドキュメントとして表示します。
クライアントから送信された情報はリクエストと呼ばれます。 次の行で始まります。
GET /17_http.html HTTP / 1.1
最初の言葉はリクエストメソッドです。 GETは、特定のリソースを取得する必要があることを意味します。 他の一般的な方法は、削除のDELETE、置換のPUT、および情報の送信のPOSTです。 サーバーは、受信した各要求を実行する必要がないことに注意してください。 ランダムなサイトを選択し、メインページを削除するように指示すると、彼はおそらく拒否します。
メソッド名の後の部分は、リクエストが送信されたリソースへのパスです。 最も単純な場合、リソースはサーバー上の単なるファイルですが、プロトコルはこの機能に限定されません。 リソースは、ファイルとして転送できるものであれば何でもかまいません。 多くのサーバーがその場で応答を作成します。 たとえば、twitter.com / marijnjhを開くと、サーバーはmarijnjhユーザーデータベースを調べ、開く場合は、そのユーザーのプロファイルページを作成します。
リソースへのパスの後、クエリの最初の行にはHTTP / 1.1が記載されており、使用するHTTPプロトコルのバージョンが報告されます。
サーバーの応答もプロトコルバージョンで始まり、応答ステータスが続きます-最初に3桁のコード、次に行。
HTTP / 1.1 200 OK
2で始まるステータスコードは、リクエストが成功したことを示します。 4で始まるコードは、何かがおかしいことを意味します。 404は最も有名なHTTPステータスであり、要求されたリソースが見つからなかったことを示します。 5で始まるコードは、サーバーでエラーが発生したことを示していますが、リクエストの障害によるものではありません。
要求または応答の最初の行の後には、任意の数のヘッダー行を続けることができます。 これらは、要求または応答に関する追加情報を示す「名前:値」の形式の文字列です。 これらのヘッダーは例に含まれています。
コンテンツの長さ:65585
コンテンツタイプ:テキスト/ html
最終変更日:2014年4月9日水曜日10:48:09 GMT
これにより、応答で受信したドキュメントのサイズとタイプが決まります。 この場合、これはサイズが65,585バイトのHTMLドキュメントです。 また、ドキュメントが最後に変更された日時も示します。
ほとんどの場合、要求または応答に含めるヘッダーをクライアントまたはサーバーが決定しますが、一部のヘッダーは必須です。 たとえば、1つのサーバーが同じIPアドレスで多くのホスト名を提供できるため、ホスト名を示すホストをリクエストに含める必要があります。このヘッダーがないと、サーバーはクライアントが通信しようとしているホストを認識しません。
ヘッダーの後に、要求と応答の両方が空の行を示し、その後に送信データを含む本文が続く場合があります。 GETおよびDELETE要求は追加データを転送しませんが、PUTおよびPOSTは送信します。 エラーメッセージなどの一部の応答には、本文は必要ありません。
ブラウザーとHTTP
例で見たように、アドレスバーにURLを入力すると、ブラウザーはリクエストを送信します。 受信したHTMLドキュメントに画像やJavaScriptファイルなどの他のファイルへの参照が含まれている場合、それらもサーバーから要求されます。
平均的な手のWebサイトには、10〜200個のリソースを簡単に含めることができます。 より速くリクエストできるようにするために、ブラウザは同時に複数のリクエストを行い、リクエストが次々に終了するのを待ちません。 このようなドキュメントは、常にGETリクエストを通じてリクエストされます。
HTMLページには、ユーザーが情報を入力してサーバーに送信できるフォームがあります。 フォームの例を次に示します。
<form method="GET" action="example/message.html"> <p>: <input type="text" name="name"></p> <p>:<br><textarea name="message"></textarea></p> <p><button type="submit"> </button></p> </form>
このコードは、2つのフィールドを持つフォームを記述しています。小さなフィールドは名前を要求し、大きなフィールドはメッセージとして入力します。 [送信]ボタンをクリックすると、これらのフィールドの情報がクエリ文字列にエンコードされます。 要素のメソッド属性がGETの場合、またはまったく指定されていない場合、クエリ文字列はアクションフィールドのURLに配置され、ブラウザーはこのURLを使用してGET要求を行います。
GET /example/message.html?name=Jean&message=Yes%3F HTTP / 1.1
クエリ行の先頭は疑問符で示されます。 その後、フォームフィールドの名前属性とこれらのフィールドの内容に対応する名前と値のペアがあります。 アンパサンド(&)を使用してそれらを区切ります。
この例で送信されるメッセージには、文字列「Yes?」が含まれていますが、疑問符は奇妙なコードに置き換えられています。 クエリ文字列の一部の文字はエスケープする必要があります。 疑問符を含み、code%3Fで表されます。 すべての形式には文字をエスケープする方法が必要であるという、書かれていない規則があります。 URLエンコードと呼ばれるこのルールは、パーセントの後に、文字コードを表す2桁の16進数を使用します。 10進法の3Fは63であり、これは疑問符コードです。 JavaScriptには、エンコードおよびデコード用の関数encodeURIComponentおよびdecodeURIComponentがあります。
console.log(encodeURIComponent("Hello & goodbye"));
前の例のフォームのmethod属性をPOSTに変更すると、フォームを含むHTTPリクエストはPOSTメソッドを使用して送信され、URLに追加するのではなく、リクエスト本文でリクエスト文字列を送信します。
POST /example/message.html HTTP / 1.1
コンテンツの長さ:24
コンテンツタイプ:アプリケーション/ x-www-form-urlencoded
名前=ジャン&メッセージ=はい%3F
慣例により、GETメソッドは、検索などの副作用のないクエリに使用されます。 サーバー上の何かを変更するリクエスト-新しいアカウントの作成またはメッセージの投稿は、POSTメソッドを使用して送信する必要があります。 ブラウザなどのクライアントプログラムは、POSTリクエストを行う必要がないことを認識しており、たとえば、ユーザーがすぐに必要とするコンテンツをダウンロードするなど、ユーザーに気付かれずにGETリクエストを行うこともあります。
次の章では、フォームに戻り、JavaScriptを使用してフォームを実行する方法について説明します。
XMLHttpRequest
ブラウザのJavaScriptがHTTPリクエストを作成できるインターフェイスは、XMLHttpRequestと呼ばれます(文字のサイズがどのようにジャンプするかに注意してください)。 1990年代後半にMicrosoftでInternet Explorer用に開発されました。 当時、XML形式はビジネスソフトウェアの世界で非常に人気がありました。この世界では、Microsoftは常に家庭にいると感じていました。 非常に人気があったため、XMLの省略形はHTTPを操作するためのインターフェースの名前に固定されていましたが、後者はXMLにまったく関連付けられていません。
それでも、名前は完全に無意味ではありません。 このインターフェイスを使用すると、回答をXMLドキュメントのように解析できます。 2つの異なるもの(要求と回答の解析)を1つに混ぜることは、もちろん、嫌なデザインですが、何ができるのでしょう。
XMLHttpRequestインターフェイスがInternet Explorerに追加されたとき、以前は非常に困難であったことを行うことが可能になりました。 たとえば、ユーザーがテキストボックスに何かを入力している間に、サイトはプロンプトのリストを表示し始めました。 スクリプトは、ユーザーがテキストを入力すると同時に、HTTPを介してサーバーにテキストを送信します。 可能な入力オプション用のデータベースを備えたサーバーは、エントリの中からエントリを探し、表示のためにそれらを返します。 とてもクールに見えました。サイトを操作するたびにページ全体がリロードされるのを待つことに慣れていました。
当時のもう1つの重要なブラウザであるMozilla(後のFirefox)は遅れを取りたくありませんでした。 同様のことができるようにするために、Mozillaはインターフェースを名前とともにコピーしました。 次世代のブラウザーがそれに続き、今日ではXMLHttpRequestが事実上の標準となっています。
提出依頼
単純なリクエストを送信するには、XMLHttpRequestコンストラクターでリクエストオブジェクトを作成し、openメソッドとsendメソッドを呼び出します。
var req = new XMLHttpRequest(); req.open("GET", "example/data.txt", false); req.send(null); console.log(req.responseText);
openメソッドはリクエストを設定します。 この例では、サンプル/ data.txtファイルに対してGETリクエストを行うことにしました。 プロトコル名で始まらないURL(たとえば、http :)は相対と呼ばれます。つまり、現在のドキュメントに対して相対的に解釈されます。 スラッシュ(/)で始まる場合、現在のパス(サーバー名の後の部分)を置き換えます。 それ以外の場合、現在のパスの最後のスラッシュまでの部分が相対URLの前に配置されます。
リクエストを開いた後、sendメソッドを使用して送信できます。 引数はリクエストの本文です。 GETリクエストの場合、nullが使用されます。 openの3番目の引数がfalseの場合、sendはリクエストへの応答が受信された後にのみ返されます。 応答本文を取得するには、要求オブジェクトのresponseTextプロパティを読み取ります。
応答オブジェクトから他の情報を取得できます。 ステータスコードはstatusプロパティで使用でき、ステータステキストはstatusTextにあります。 見出しはgetResponseHeaderから読み取ることができます。
var req = new XMLHttpRequest(); req.open("GET", "example/data.txt", false); req.send(null); console.log(req.status, req.statusText);
ヘッダー名は大文字と小文字が区別されません。 通常、「Content-Type」など、各単語の先頭に大文字が使用されますが、「content-type」または「cOnTeNt-TyPe」は同じタイトルを表します。
ブラウザ自体は、「ホスト」などのヘッダーを追加します。これらのヘッダーは、サーバーがボディサイズを計算するために必要です。 ただし、setRequestHeaderメソッドを使用して独自のヘッダーを追加できます。 これは特別な場合に必要であり、アクセスしているサーバーの支援が必要です-処理できないヘッダーは無視しても構いません。
非同期リクエスト
この例では、要求は送信呼び出しが終了したときに完了しました。 responseTextなどのプロパティがすぐに使用可能になるため、これは便利です。 しかし、これは、ブラウザーとサーバーが互いに通信している間、プログラムが待機することを意味します。 不十分な通信、弱いサーバー、または大きなファイルの場合、これには長い時間がかかります。 また、プログラムがスタンバイモードになっている間はイベントハンドラーが機能しないため、これは悪いことです。ドキュメントはユーザーのアクションに応答しなくなります。
openの3番目の引数としてtrueを渡すと、リクエストは非同期になります。 つまり、sendを呼び出すと、リクエストは送信のためにキューに入れられます。 プログラムは引き続き動作し、ブラウザはバックグラウンドでデータを送受信します。
ただし、リクエストの処理中は、応答を受け取りません。 データが到着して準備ができているという通知メカニズムが必要です。 これを行うには、「load」イベントをリッスンする必要があります。
var req = new XMLHttpRequest(); req.open("GET", "example/data.txt", true); req.addEventListener("load", function() { console.log("Done:", req.status); }); req.send(null);
第15章のrequestAnimationFrameを呼び出すように、このコードは非同期プログラミングスタイルを使用するように強制し、リクエスト後にコードを実行するように関数をラップし、適切なタイミングでこの関数の呼び出しを配置します。 これについては後で説明します。
XMLデータの取得
XMLHttpRequestによって返されるリソースがXMLドキュメントの場合、responseXMLプロパティにはドキュメントの解析されたビューが含まれます。 スタイルプロパティのような固有のHTML機能がないことを除いて、DOMと同様の方法で機能します。 responseXMLに含まれるオブジェクトは、ドキュメントオブジェクトに対応します。 そのdocumentElementプロパティは、外部XMLドキュメントタグを参照します。 次のドキュメント(例/ fruit.xml)では、このタグは次のようになります。
<fruits> <fruit name="banana" color="yellow"/> <fruit name="lemon" color="yellow"/> <fruit name="cherry" color="red"/> </fruits>
次のようなファイルを取得できます。
var req = new XMLHttpRequest(); req.open("GET", "example/fruit.xml", false); req.send(null); console.log(req.responseXML.querySelectorAll("fruit").length);
XMLドキュメントを使用して、構造化された情報をサーバーと交換できます。 それらの形式-ネストされたタグ-は、ほとんどのデータを保存するのに適しています。少なくともテキストファイルよりも優れています。 DOMインターフェースは、情報を抽出するという点では不格好であり、XML文書はかなり冗長です。 通常は、プログラムと人の両方の読み取りと書き込みが簡単なJSON形式のデータを使用して通信することをお勧めします。
var req = new XMLHttpRequest(); req.open("GET", "example/fruit.json", false); req.send(null); console.log(JSON.parse(req.responseText));
HTTPのサンドボックス
WebページからのHTTP要求は、セキュリティ上の問題を引き起こします。 スクリプトを制御している人は、実行中のコンピューターを所有しているユーザーの興味とは異なる興味を持つ場合があります。 具体的には、themafia.orgにアクセスした場合、ブラウザの情報を識別子として使用し、すべてのお金をマフィアアカウントに送信するコマンドを与えて、スクリプトがmybank.comにリクエストできるようにしたくありません。
Webサイトはこのような攻撃から身を守ることができますが、これにはある程度の努力が必要であり、多くのサイトはこれに対処していません。 このため、ブラウザは、スクリプトが他のドメイン(themafia.orgやmybank.comなどの名前)にリクエストを送信することを防ぐことで、それらを保護します。
これは、正当な理由で異なるドメインにアクセスする必要があるシステムの開発を妨げる可能性があります。 幸いなことに、サーバーは応答に次のヘッダーを含めることができ、リクエストが他のドメインから送信される可能性があることをブラウザーに説明します。
Access-Control-Allow-Origin:*
抽象リクエスト
第10章では、AMDモジュラーシステムの実装で、仮想関数backgroundReadFileを使用しました。 彼女はファイル名と関数を受け入れ、ファイルの内容を読み取った後にこの関数を呼び出しました。 この関数の簡単な実装は次のとおりです。
function backgroundReadFile(url, callback) { var req = new XMLHttpRequest(); req.open("GET", url, true); req.addEventListener("load", function() { if (req.status < 400) callback(req.responseText); }); req.send(null); }
単純な抽象化により、単純なGET要求に対するXMLHttpRequestの使用が簡素化されます。 HTTPリクエストを行うプログラムを作成している場合、ヘルパー関数を使用すると、niceいXMLHttpRequestテンプレートを常に繰り返す必要がなくなります。
コールバック引数は、このような関数を説明するためによく使用される用語です。 後でコールバックできるように、コールバック関数は別のコードに渡されます。
プログラム専用に調整された補助HTTP関数を簡単に作成できます。 前のものはGETリクエストのみを行い、リクエストのヘッダーまたは本文を制御することはできません。 POSTリクエスト用に別のオプション、または異なるリクエストをサポートするより一般的なオプションを作成できます。 多くのJavaScriptライブラリは、XMLHttpRequestのラッパーを提供します。
このラッパーの主な問題はエラー処理です。 要求がエラーを示すステータスコード(400以上)を返す場合、何もしません。 これは正常な場合もありますが、情報を受信していることを示すダウンロードインジケーターをページに配置したとします。 サーバーがクラッシュしたか接続が中断されたためにリクエストが失敗した場合、ページは何かでビジーであるように見せます。 ユーザーは少し待ってから退屈し、サイトがなんらかの愚かだと判断します。
アクションを実行できるように、失敗したリクエストに関する警告を受け取るオプションが必要です。 たとえば、ダウンロードメッセージを削除して、ユーザーに何か問題があったことを伝えることができます。
非同期コードのエラー処理は、同期コードよりもさらに複雑です。 多くの場合、作業の一部を分離してコールバック関数に配置する必要があるため、tryブロックのスコープは無意味になります。 次のコードでは、backgroundReadFileの呼び出しがすぐに返されるため、例外はキャッチされません。 その後、コントロールはtryブロックを離れ、そこからの関数は呼び出されません。
try { backgroundReadFile("example/data.txt", function(text) { if (text != "expected") throw new Error("That was unexpected"); }); } catch (e) { console.log("Hello from the catch block"); }
失敗したリクエストを処理するには、追加の関数をラッパーに渡し、問題が発生した場合にそれを呼び出す必要があります。 別のオプションは、要求が失敗した場合、問題の説明を含む追加の引数がコールバック関数に渡されるという規則を使用することです。 例:
function getURL(url, callback) { var req = new XMLHttpRequest(); req.open("GET", url, true); req.addEventListener("load", function() { if (req.status < 400) callback(req.responseText); else callback(null, new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(null, new Error("Network error")); }); req.send(null); }
呼び出しに問題がある場合に起動するエラーイベントハンドラーを追加しました。 また、リクエストがエラーを示すステータスで完了すると、エラー引数を使用してコールバック関数を呼び出します。
getURLを使用するコードは、エラーが返されたかどうかを確認し、エラーがある場合は処理する必要があります。
getURL("data/nonsense.txt", function(content, error) { if (error != null) console.log("Failed to fetch nonsense.txt: " + error); else console.log("nonsense.txt: " + content); });
例外を除き、これは役に立ちません。 複数の非同期アクションを連続して実行すると、(try / catchブロックで各ハンドラーをラップしていない限り)チェーン内の任意の時点で例外がトップレベルで発生し、チェーン全体に割り込みます。
約束
単純なコールバックの形式で複雑なプロジェクトの非同期コードを記述することは困難です。 エラーチェックを忘れたり、予期しない例外がプログラムを突然中断したりすることは非常に簡単です。 さらに、正しいエラー処理を整理し、いくつかの連続したコールバックを通じてエラーを渡すことは非常に面倒です。
追加の抽象化を使用して、この問題を解決するために多くの試みが行われました。 最も成功した試みの1つはプロミスと呼ばれます。 Promiseは、渡すことができるオブジェクトで非同期アクションをラップし、アクションが完了または失敗したときに特定のことを行う必要があります。 このようなインターフェースはすでにJavaScriptの現在のバージョンの一部になっており、古いバージョンではライブラリとして使用できます。
promiseインターフェースは特に直感的ではありませんが、強力です。 この章では、部分的にのみ説明します。 詳細については、
www.promisejs.orgをご覧ください。
promisesオブジェクトを作成するには、Promiseコンストラクターを呼び出して、非同期アクションを初期化する機能を与えます。 コンストラクターはこの関数を呼び出し、2つの引数を渡します。これらの引数自体も関数です。 最初は成功した場合に呼び出され、もう一方は失敗した場合に呼び出されます。
また、GETリクエストのラッパーもありますが、今回はこれが約束を返します。 今ではgetと呼ぶだけです。
function get(url) { return new Promise(function(succeed, fail) { var req = new XMLHttpRequest(); req.open("GET", url, true); req.addEventListener("load", function() { if (req.status < 400) succeed(req.responseText); else fail(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { fail(new Error("Network error")); }); req.send(null); }); }
関数自体へのインターフェースが簡素化されていることに注意してください。 彼女にURLを渡すと、彼女は約束を返します。 要求の出力のハンドラーとして機能します。 thenメソッドがあり、2つの関数で呼び出されます。1つは処理の成功、もう1つは失敗です。
get("example/data.txt").then(function(text) { console.log("data.txt: " + text); }, function(error) { console.log("Failed to fetch data.txt: " + error); });
これまでのところ、これはまだ私たちがすでにやったことを表現する1つの方法です。 一連のイベントがある場合にのみ、顕著な違いが見えるようになります。
呼び出しは新しいプロミスを生成し、その結果(成功ハンドラーに渡される値)は、次に渡した最初の関数によって返される値に依存します。 この関数は、追加の非同期作業が行われていることを示す別のプロミスを返すことができます。 この場合、そのときに返されるpromiseは、ハンドラー関数によって返されるpromiseを待機し、同じ値で成功または失敗が発生します。 ハンドラー関数がプロミスではない値を返すと、thenが返すプロミスは成功し、その値を結果として使用します。
そのため、promiseの結果を変更するために使用できます。 たとえば、次の関数は、結果がJSONとして解析された特定のURLのコンテンツであるプロミスを返します。
function getJSON(url) { return get(url).then(JSON.parse); }
thenへの最後の呼び出しは、失敗ハンドラーを示していませんでした。 これは許容されます。 エラーはそれまでに返されたプロミスに転送され、それが必要になります。getJSONは何かがうまくいかなかったときに何をすべきかを知りませんが、それを呼び出すコードはそれを知っていることが望まれます。
promiseの使用を示す例として、サーバーからJSONファイルの数を受け取り、リクエストの実行中に「ダウンロード」という単語を表示するプログラムを作成します。 ファイルには、人に関する情報と、父親、母親、配偶者などの他の人に関する情報を含む他のファイルへのリンクが含まれています。
example / bert.jsonから配偶者の母親の名前を取得する必要があります。 問題が発生した場合は、「ダウンロード」というテキストを削除してエラーメッセージを表示する必要があります。 約束でそれを行う方法は次のとおりです。
<script> function showMessage(msg) { var elt = document.createElement("div"); elt.textContent = msg; return document.body.appendChild(elt); } var loading = showMessage("..."); getJSON("example/bert.json").then(function(bert) { return getJSON(bert.spouse); }).then(function(spouse) { return getJSON(spouse.mother); }).then(function(mother) { showMessage(" - " + mother.name); }).catch(function(error) { showMessage(String(error)); }).then(function() { document.body.removeChild(loading); }); </script>
結果のプログラムは比較的コンパクトで読みやすいです。 catchメソッドはthenに似ていますが、失敗した結果のハンドラーのみを想定し、成功した場合は変更されていない結果をさらに渡します。 プログラムの実行は、例外をキャッチした後、通常の方法で続行されます-try / catchの場合と同じです。 したがって、ブートメッセージを削除する最後の処理は、障害が発生した場合でも実行されます。
promiseインターフェースは、プログラムの実行を非同期に処理するための別個の言語であると想像できます。 操作に必要なメソッドと関数への追加の呼び出しは、コードに多少奇妙な外観を与えますが、すべてのエラーを手動で処理するほど不便ではありません。
HTTPを評価する
ブラウザ(クライアント)のJavaScriptプログラムがサーバープログラムと通信するシステムを作成する場合、そのような通信のいくつかのモデリングオプションを使用できます。
一般的な方法は、リモートプロシージャコールです。 このモデルでは、通信は通常の関数呼び出しのパターンに従って進行し、これらの関数のみが別のコンピューターで実行されます。
呼び出しは、関数名と引数を含むサーバーへの要求を作成することです。要求への応答には戻り値が含まれます。リモートプロシージャコールを使用する場合、HTTPは通信の手段としてのみ機能し、ほとんどの場合、完全に非表示にする抽象化レイヤーを記述します。別のアプローチは、HTTPリソースとメソッドの概念に基づいて通信システムを構築することです。 addUserというリモートプロシージャを呼び出す代わりに、/ users / larryに対してPUT要求を行います。関数の引数でユーザープロパティをエンコードする代わりに、ドキュメント形式を定義するか、ユーザーを表す既存の形式を使用します。新しいリソースを作成するPUT要求の本文は、単にこの形式のドキュメントになります。リソースは、URL(/ user / larry)へのGETリクエストを通じて取得され、このリソースを表すドキュメントが返されます。2番目のアプローチは、リソースキャッシングのサポートなど、いくつかのHTTP機能の使用を簡素化します(リソースのコピーはクライアント側に保存されます)。また、リソースの観点から考えることは、機能の観点から考えるよりも簡単なので、一貫性のあるインターフェースを作成するのにも役立ちます。セキュリティとHTTPS
データは、長く危険な経路に沿ってインターネットを移動します。目的地に着くには、コーヒーショップのWi-Fiネットワークからさまざまな組織や州が管理するネットワークに至るまで、あらゆる場所をジャンプする必要があります。途中のどの時点でも、それらを読み取ったり、変更することさえできます。メールパスワードなどの秘密を保持する必要がある場合、または送金先の銀行口座番号など、目的地に変更する必要がない場合、単純なHTTPでは不十分です。URLがhttps://で始まるセキュアHTTPプロトコルは、HTTPトラフィックをラップするため、読み取りや変更が困難になります。最初に、クライアントはサーバーが主張するとおりであることを確認し、ブラウザーが認識した権限のある当事者が発行した暗号証明書を提示することをサーバーに要求します。次に、接続を通過するすべてのデータが暗号化され、盗聴や改ざんが防止されます。したがって、すべてが正常に機能する場合、HTTPSは、誰かが通信している別のWebサイトのふりをする場合と、通信の傍受の場合の両方を防ぎます。それは完全ではなく、偽の証明書や盗まれた証明書、または壊れたプログラムが原因でHTTPSが作業に対応できなかったケースがすでにあります。それでも、HTTPを使用すると、何か悪いことが非常に簡単に行われます。また、HTTPSをハッキングするには、政府機関または非常に深刻な犯罪組織のみが適用できる努力が必要です(これらの組織にまったく違いがない場合もあります)。まとめ
この章では、HTTPがインターネット上のリソースにアクセスするためのプロトコルであることを確認しました。クライアントは、メソッド(通常はGET)とリソースを定義するパスを含む要求を送信します。サーバーは要求の処理方法を決定し、ステータスコードと応答本文で応答します。要求と応答には、追加情報を伝えるヘッダーが含まれる場合があります。ブラウザは、ページをレンダリングするために必要なリソースを取得するためにGET要求を行います。このページには、ユーザーが入力した情報を、フォームの送信後に作成されるリクエストで送信できるフォームが含まれている場合があります。これについては、次の章で詳しく説明します。JavaScriptがブラウザからHTTP要求を作成するためのインターフェイスは、XMLHttpRequestと呼ばれます。XMLプレフィックスは無視できます(ただし、それを記述する必要があります)。これは、要求が完了するまですべての作業をブロックする同期と、要求の終了を監視するイベントハンドラーのインストールを必要とする非同期の2つの方法で使用できます。ほとんどすべての場合、非同期方式が優先されます。クエリの作成は次のようになります。 var req = new XMLHttpRequest(); req.open("GET", "example/data.txt", true); req.addEventListener("load", function() { console.log(req.statusCode); }); req.send(null);
非同期プログラミングは簡単なことではありません。Promisesは、エラーメッセージと例外を適切なハンドラーにルーティングし、重複するエラーを起こしやすい要素を抽象化するのを支援する、よりシンプルなインターフェイスです。演習
コンテンツ交渉
HTTPでできることの1つですが、まだ説明していませんが、コンテンツネゴシエーションです。要求のAcceptヘッダーを使用して、クライアントが受信したいドキュメントの種類をサーバーに伝えることができます。多くのサーバーはそれを無視しますが、サーバーがリソースをエンコードするさまざまな方法を知っているとき、サーバーはヘッダーを見て、クライアントが好むヘッダーを送信できます。eloquentjavascript.net/author URLは、クライアントの要求に応じて、プレーンテキストとHTMLまたはJSONで応答するように構成されます。これらの形式は、標準化されたコンテンツタイプtext / plain、text / html、およびapplication / jsonによって定義されます。このリソースの3つの形式すべてを受信する要求を送信します。XMLHttpRequestオブジェクトのsetRequestHeaderメソッドを使用して、Acceptヘッダーを目的のコンテンツタイプのいずれかに設定します。開いた後、送信する前にヘッダーを設定してください。最後に、アプリケーション/虹+ユニコーンなどのコンテンツを要求して、何が起こるかを確認してください。いくつかの約束を待っています
Promiseコンストラクターにはallメソッドがあり、promiseの配列を受け取ると、配列に指定されたすべてのpromiseの完了を待つpromiseを返します。次に、成功した結果を返し、結果を含む配列を返します。配列内のプロミスのいずれかが失敗した場合、一般的なプロミスも失敗を返します(失敗したプロミスの値が配列から返されます)。all関数を記述して、このようなことを試してください。Promiseが完了した後(正常に完了した場合またはエラーが発生した場合)、エラーまたは成功を再び返すことはできず、それ以降の関数呼び出しは無視されます。これにより、約束のエラー処理を簡素化できます。 function all(promises) { return new Promise(function(success, fail) {