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-Encoding
Access-Control-Request-Headers
Access-Control-Request-Method
Connection
Content-Length
Cookie
、Cookie2
Date
DNT
Expect
Host
Keep-Alive
Origin
Referer
TE
Trailer
Transfer-Encoding
Upgrade
Via
Proxy-*
Sec-*
これらのヘッダーは、適切で安全なHTTPを確保するため、ブラウザによってのみ制御されます。
POSTリクエスト
POST
リクエスト、または別のメソッドのリクエストを行うには、fetch
オプションを使用する必要があります。
method
– HTTPメソッド、例:POST
body
– リクエスト本文、次のいずれか- 文字列(例: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の場合はtrue
response.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…)を使用します。