JavaScriptはサーバーにネットワークリクエストを送信し、必要なときにいつでも新しい情報をロードできます。
たとえば、ネットワークリクエストを使用して以下を行うことができます。
- 注文を送信する
- ユーザー情報をロードする
- サーバーから最新の更新を受信する
- など
…そして、これらすべてはページをリロードすることなく実行できます!
JavaScriptからのネットワークリクエストには、「AJAX」(Asynchronous JavaScript And XMLの略)という包括的な用語があります。ただし、XMLを使用する必要はありません。この用語は古い時代に由来するため、その単語が含まれています。この用語をすでに聞いたことがあるかもしれません。
ネットワークリクエストを送信してサーバーから情報を取得するには、複数の方法があります。
fetch()メソッドは最新かつ多用途であるため、まずはそれから始めます。古いブラウザではサポートされていません(ポリフィルできます)が、最新のブラウザでは非常によくサポートされています。
基本的な構文は次のとおりです。
let promise = fetch(url, [options])
url– アクセスするURL。options– オプションのパラメータ:メソッド、ヘッダーなど。
optionsがない場合、これは単純なGETリクエストであり、urlの内容をダウンロードします。
ブラウザはすぐにリクエストを開始し、呼び出し元のコードが結果を取得するために使用するpromiseを返します。
レスポンスの取得は、通常2段階のプロセスです。
まず、fetchによって返されたpromiseは、サーバーがヘッダーで応答するとすぐに、組み込みのResponseクラスのオブジェクトで解決されます。
この段階では、HTTPステータスを確認して成功したかどうかを確認し、ヘッダーを確認できますが、まだ本文はありません。
ネットワークの問題やサイトが存在しないなど、fetchがHTTPリクエストを実行できなかった場合、promiseは拒否されます。404や500などの異常なHTTPステータスはエラーを引き起こしません。
レスポンスプロパティでHTTPステータスを確認できます
status– HTTPステータスコード、例:200。ok– ブール値、HTTPステータスコードが200〜299の場合はtrue。
例えば
let response = await fetch(url);
if (response.ok) { // if HTTP-status is 200-299
// get the response body (the method explained below)
let json = await response.json();
} else {
alert("HTTP-Error: " + response.status);
}
次に、レスポンス本文を取得するには、追加のメソッド呼び出しを使用する必要があります。
Responseは、さまざまな形式で本文にアクセスするための、複数のpromiseベースのメソッドを提供します。
response.text()– レスポンスを読み取り、テキストとして返すresponse.json()– レスポンスをJSONとして解析するresponse.formData()– レスポンスをFormDataオブジェクトとして返す(次の章で説明)response.blob()– レスポンスをBlob(タイプ付きのバイナリデータ)として返すresponse.arrayBuffer()– レスポンスをArrayBuffer(バイナリデータの低レベル表現)として返す- さらに、
response.bodyはReadableStreamオブジェクトであり、本文をチャンクごとに読み取ることができます。後ほど例を示します。
たとえば、GitHubから最新のコミットを含むJSONオブジェクトを取得してみましょう。
let url = 'https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits';
let response = await fetch(url);
let commits = await response.json(); // read response body and parse as JSON
alert(commits[0].author.login);
または、awaitを使用せずに、純粋なpromise構文を使用しても同じです。
fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits')
.then(response => response.json())
.then(commits => alert(commits[0].author.login));
レスポンステキストを取得するには、.json()の代わりにawait response.text()を使用します。
let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits');
let text = await response.text(); // read response body as text
alert(text.slice(0, 80) + '...');
バイナリ形式での読み取りの例として、“fetch”仕様のロゴ画像をフェッチして表示してみましょう(Blobの操作の詳細については、Blobの章を参照)。
let response = await fetch('/article/fetch/logo-fetch.svg');
let blob = await response.blob(); // download as Blob object
// create <img> for it
let img = document.createElement('img');
img.style = 'position:fixed;top:10px;left:10px;width:100px';
document.body.append(img);
// show it
img.src = URL.createObjectURL(blob);
setTimeout(() => { // hide after three seconds
img.remove();
URL.revokeObjectURL(img.src);
}, 3000);
本文を読み取るメソッドは1つだけ選択できます。
response.text()でレスポンスをすでに取得している場合、本文の内容はすでに処理されているため、response.json()は機能しません。
let text = await response.text(); // response body consumed
let parsed = await response.json(); // fails (already consumed)
レスポンスヘッダー
レスポンスヘッダーは、response.headersのMapのようなヘッダーオブジェクトで利用できます。
これは正確にはMapではありませんが、名前で個々のヘッダーを取得したり、それらを反復処理したりするための同様のメソッドがあります。
let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits');
// get one header
alert(response.headers.get('Content-Type')); // application/json; charset=utf-8
// iterate over all headers
for (let [key, value] of response.headers) {
alert(`${key} = ${value}`);
}
リクエストヘッダー
fetchでリクエストヘッダーを設定するには、headersオプションを使用できます。送信ヘッダーを含むオブジェクトがあり、次のようになります。
let response = fetch(protectedUrl, {
headers: {
Authentication: 'secret'
}
});
…ただし、設定できない禁止されたHTTPヘッダーのリストがあります。
Accept-Charset、Accept-EncodingAccess-Control-Request-HeadersAccess-Control-Request-MethodConnectionContent-LengthCookie、Cookie2DateDNTExpectHostKeep-AliveOriginRefererTETrailerTransfer-EncodingUpgradeViaProxy-*Sec-*
これらのヘッダーは、適切で安全なHTTPを確保するため、ブラウザによってのみ制御されます。
POSTリクエスト
POSTリクエスト、または別のメソッドのリクエストを行うには、fetchオプションを使用する必要があります。
method– HTTPメソッド、例:POSTbody– リクエスト本文、次のいずれか- 文字列(例:JSONエンコード)
FormDataオブジェクト、データをmultipart/form-dataとして送信するBlob/BufferSource、バイナリデータを送信する- URLSearchParams、データを
x-www-form-urlencodedエンコーディングで送信する(まれに使用される)
ほとんどの場合、JSON形式が使用されます。
たとえば、このコードはuserオブジェクトをJSONとして送信します。
let user = {
name: 'John',
surname: 'Smith'
};
let response = await fetch('/article/fetch/post/user', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(user)
});
let result = await response.json();
alert(result.message);
リクエストbodyが文字列の場合、Content-Typeヘッダーはデフォルトでtext/plain;charset=UTF-8に設定されることに注意してください。
ただし、JSONを送信するため、headersオプションを使用して、JSONエンコードデータの正しいContent-Typeであるapplication/jsonを送信します。
画像の送信
BlobまたはBufferSourceオブジェクトを使用して、fetchでバイナリデータを送信することもできます。
この例では、マウスを上に移動することで描画できる<canvas>があります。「送信」ボタンをクリックすると、画像がサーバーに送信されます。
<body style="margin:0">
<canvas id="canvasElem" width="100" height="80" style="border:1px solid"></canvas>
<input type="button" value="Submit" onclick="submit()">
<script>
canvasElem.onmousemove = function(e) {
let ctx = canvasElem.getContext('2d');
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
};
async function submit() {
let blob = await new Promise(resolve => canvasElem.toBlob(resolve, 'image/png'));
let response = await fetch('/article/fetch/post/image', {
method: 'POST',
body: blob
});
// the server responds with confirmation and the image size
let result = await response.json();
alert(result.message);
}
</script>
</body>
Blobオブジェクトには組み込みのタイプ(ここではtoBlobによって生成されたimage/png)があるため、ここではContent-Typeヘッダーを手動で設定しないことに注意してください。Blobオブジェクトの場合、そのタイプはContent-Typeの値になります。
submit()関数は、async/awaitなしで次のように書き直すことができます。
function submit() {
canvasElem.toBlob(function(blob) {
fetch('/article/fetch/post/image', {
method: 'POST',
body: blob
})
.then(response => response.json())
.then(result => alert(JSON.stringify(result, null, 2)))
}, 'image/png');
}
まとめ
典型的なfetchリクエストは、2つのawait呼び出しで構成されます。
let response = await fetch(url, options); // resolves with response headers
let result = await response.json(); // read body as json
または、awaitなしで
fetch(url, options)
.then(response => response.json())
.then(result => /* process result */)
レスポンスプロパティ
response.status– レスポンスのHTTPコードresponse.ok– ステータスが200〜299の場合はtrueresponse.headers– HTTPヘッダーを含むMapのようなオブジェクト
レスポンス本文を取得するメソッド
response.text()– レスポンスをテキストとして返すresponse.json()– レスポンスをJSONオブジェクトとして解析するresponse.formData()– レスポンスをFormDataオブジェクトとして返す(multipart/form-dataエンコーディング、次の章を参照)response.blob()– レスポンスをBlob(タイプ付きのバイナリデータ)として返すresponse.arrayBuffer()– レスポンスをArrayBuffer(低レベルのバイナリデータ)として返す
これまでのFetchオプション
method– HTTPメソッドheaders– リクエストヘッダーを含むオブジェクト(すべてのヘッダーが許可されるわけではない)body– 送信するデータ(リクエスト本文)をstring、FormData、BufferSource、Blob、またはUrlSearchParamsオブジェクトとして
次の章では、fetchのより多くのオプションとユースケースについて説明します。
コメント
<code>タグを使用します。数行の場合は、<pre>タグで囲みます。10行を超える場合は、サンドボックス(plnkr、jsbin、codepen…)を使用します。