JavaScript Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑпÑавлÑÑÑ ÑеÑевÑе запÑоÑÑ Ð½Ð° ÑеÑÐ²ÐµÑ Ð¸ подгÑÑжаÑÑ Ð½Ð¾Ð²ÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¿Ð¾ меÑе Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ÑÑи.
ÐапÑимеÑ, Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ иÑполÑзоваÑÑ ÑеÑевой запÑоÑ, ÑÑобÑ:
- ÐÑпÑавиÑÑ Ð·Ð°ÐºÐ°Ð·,
- ÐагÑÑзиÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾ полÑзоваÑеле,
- ÐапÑоÑиÑÑ Ð¿Ð¾Ñледние Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñ ÑеÑвеÑа,
- â¦Ð¸ Ñ.п.
ÐÐ»Ñ ÑеÑевÑÑ Ð·Ð°Ð¿ÑоÑов из JavaScript еÑÑÑ ÑиÑоко извеÑÑнÑй ÑеÑмин «AJAX» (аббÑевиаÑÑÑа Ð¾Ñ Asynchronous JavaScript And XML). XML Ð¼Ñ Ð¸ÑполÑзоваÑÑ Ð½Ðµ обÑзанÑ, пÑоÑÑо ÑеÑмин ÑÑаÑÑй, поÑÑÐ¾Ð¼Ñ Ð² нÑм еÑÑÑ ÑÑо Ñлово. Ðозможно, Ð²Ñ ÐµÐ³Ð¾ Ñже где-Ñо ÑлÑÑали.
ÐÑÑÑ Ð½ÐµÑколÑко ÑпоÑобов делаÑÑ ÑеÑевÑе запÑоÑÑ Ð¸ полÑÑаÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ñ ÑеÑвеÑа.
ÐеÑод fetch() â ÑовÑеменнÑй и оÑÐµÐ½Ñ Ð¼Ð¾ÑнÑй, поÑÑÐ¾Ð¼Ñ Ð½Ð°ÑнÑм Ñ Ð½ÐµÐ³Ð¾. Ðн не поддеÑживаеÑÑÑ ÑÑаÑÑми (можно иÑполÑзоваÑÑ Ð¿Ð¾Ð»Ð¸Ñил), но поддеÑживаеÑÑÑ Ð²Ñеми ÑовÑеменнÑми бÑаÑзеÑами.
ÐазовÑй ÑинÑакÑиÑ:
let promise = fetch(url, [options])
urlâ URL Ð´Ð»Ñ Ð¾ÑпÑавки запÑоÑа.optionsâ дополниÑелÑнÑе паÑамеÑÑÑ: меÑод, заголовки и Ñак далее.
Ðез options ÑÑо пÑоÑÑой GET-запÑоÑ, ÑкаÑиваÑÑий ÑодеÑжимое по адÑеÑÑ url.
ÐÑаÑÐ·ÐµÑ ÑÑÐ°Ð·Ñ Ð¶Ðµ наÑÐ¸Ð½Ð°ÐµÑ Ð·Ð°Ð¿ÑÐ¾Ñ Ð¸ возвÑаÑÐ°ÐµÑ Ð¿ÑомиÑ, коÑоÑÑй внеÑний код иÑполÑзÑÐµÑ Ð´Ð»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ ÑезÑлÑÑаÑа.
ÐÑоÑеÑÑ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ Ð¾ÑвеÑа обÑÑно пÑоиÑÑ Ð¾Ð´Ð¸Ñ Ð² два ÑÑапа.
Ðо-пеÑвÑÑ
, promise вÑполнÑеÑÑÑ Ñ Ð¾Ð±ÑекÑом вÑÑÑоенного клаÑÑа Response в каÑеÑÑве ÑезÑлÑÑаÑа, как ÑолÑко ÑеÑÐ²ÐµÑ Ð¿ÑиÑлÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¸ оÑвеÑа.
Ðа ÑÑом ÑÑапе Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ пÑовеÑиÑÑ ÑÑаÑÑÑ HTTP-запÑоÑа и опÑеделиÑÑ, вÑполнилÑÑ Ð»Ð¸ он ÑÑпеÑно, а Ñакже поÑмоÑÑеÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¸, но пока без Ñела оÑвеÑа.
ÐÑÐ¾Ð¼Ð¸Ñ Ð·Ð°Ð²ÐµÑÑаеÑÑÑ Ñ Ð¾Ñибкой, еÑли fetch не Ñмог вÑполниÑÑ HTTP-запÑоÑ, напÑÐ¸Ð¼ÐµÑ Ð¿Ñи оÑибке ÑеÑи или еÑли Ð½ÐµÑ Ñакого ÑайÑа. HTTP-ÑÑаÑÑÑÑ 404 и 500 не ÑвлÑÑÑÑÑ Ð¾Ñибкой.
ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ ÑвидеÑÑ HTTP-ÑÑаÑÑÑ Ð² ÑвойÑÑÐ²Ð°Ñ Ð¾ÑвеÑа:
statusâ код ÑÑаÑÑÑа HTTP-запÑоÑа, напÑÐ¸Ð¼ÐµÑ 200.okâ логиÑеÑкое знаÑение: бÑдеÑtrue, еÑли код HTTP-ÑÑаÑÑÑа в диапазоне 200-299.
ÐапÑимеÑ:
let response = await fetch(url);
if (response.ok) { // еÑли HTTP-ÑÑаÑÑÑ Ð² диапазоне 200-299
// полÑÑаем Ñело оÑвеÑа (Ñм. пÑо ÑÑÐ¾Ñ Ð¼ÐµÑод ниже)
let json = await response.json();
} else {
alert("ÐÑибка HTTP: " + response.status);
}
Ðо-вÑоÑÑÑ , Ð´Ð»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ Ñела оÑвеÑа нам нÑжно иÑполÑзоваÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑй вÑзов меÑода.
Response пÑедоÑÑавлÑÐµÑ Ð½ÐµÑколÑко меÑодов, оÑнованнÑÑ
на пÑомиÑаÑ
, Ð´Ð»Ñ Ð´Ð¾ÑÑÑпа к ÑÐµÐ»Ñ Ð¾ÑвеÑа в ÑазлиÑнÑÑ
ÑоÑмаÑаÑ
:
response.text()â ÑиÑÐ°ÐµÑ Ð¾ÑÐ²ÐµÑ Ð¸ возвÑаÑÐ°ÐµÑ ÐºÐ°Ðº обÑÑнÑй ÑекÑÑ,response.json()â декодиÑÑÐµÑ Ð¾ÑÐ²ÐµÑ Ð² ÑоÑмаÑе JSON,response.formData()â возвÑаÑÐ°ÐµÑ Ð¾ÑÐ²ÐµÑ ÐºÐ°Ðº обÑекÑFormData(ÑазбеÑÑм его в ÑледÑÑÑей главе),response.blob()â возвÑаÑÐ°ÐµÑ Ð¾Ð±ÑÐµÐºÑ ÐºÐ°Ðº Blob (бинаÑнÑе даннÑе Ñ Ñипом),response.arrayBuffer()â возвÑаÑÐ°ÐµÑ Ð¾ÑÐ²ÐµÑ ÐºÐ°Ðº ArrayBuffer (низкоÑÑовневое пÑедÑÑавление бинаÑнÑÑ Ð´Ð°Ð½Ð½ÑÑ ),- помимо ÑÑого,
response.bodyâ ÑÑо обÑÐµÐºÑ ReadableStream, Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ ÐºÐ¾ÑоÑого можно ÑÑиÑÑваÑÑ Ñело запÑоÑа по ÑаÑÑÑм. ÐÑ ÑаÑÑмоÑÑим и Ñакой пÑÐ¸Ð¼ÐµÑ Ð½ÐµÑколÑко позже.
ÐапÑимеÑ, полÑÑим JSON-обÑÐµÐºÑ Ñ Ð¿Ð¾Ñледними коммиÑами из ÑепозиÑоÑÐ¸Ñ Ð½Ð° GitHub:
let url = 'https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits';
let response = await fetch(url);
let commits = await response.json(); // ÑиÑаем оÑÐ²ÐµÑ Ð² ÑоÑмаÑе JSON
alert(commits[0].author.login);
То же Ñамое без await, Ñ Ð¸ÑполÑзованием пÑомиÑов:
fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits')
.then(response => response.json())
.then(commits => alert(commits[0].author.login));
ÐÐ»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ Ð¾ÑвеÑа в виде ÑекÑÑа иÑполÑзÑем await response.text() вмеÑÑо .json():
let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits');
let text = await response.text(); // пÑоÑиÑаÑÑ Ñело оÑвеÑа как ÑекÑÑ
alert(text.slice(0, 80) + '...');
РкаÑеÑÑве пÑимеÑа ÑабоÑÑ Ñ Ð±Ð¸Ð½Ð°ÑнÑми даннÑми, давайÑе запÑоÑим и вÑведем на ÑкÑан логоÑип ÑпеÑиÑикаÑии «fetch» (Ñм. Ð³Ð»Ð°Ð²Ñ Blob, ÑÑÐ¾Ð±Ñ ÑзнаÑÑ Ð¿Ñо опеÑаÑии Ñ Blob):
let response = await fetch('/article/fetch/logo-fetch.svg');
let blob = await response.blob(); // ÑкаÑиваем как Blob-обÑекÑ
// ÑоздаÑм <img>
let img = document.createElement('img');
img.style = 'position:fixed;top:10px;left:10px;width:100px';
document.body.append(img);
// вÑводим на ÑкÑан
img.src = URL.createObjectURL(blob);
setTimeout(() => { // пÑÑÑем ÑеÑез ÑÑи ÑекÑндÑ
img.remove();
URL.revokeObjectURL(img.src);
}, 3000);
ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ вÑбÑаÑÑ ÑолÑко один меÑод ÑÑÐµÐ½Ð¸Ñ Ð¾ÑвеÑа.
ÐÑли Ð¼Ñ Ñже полÑÑили оÑÐ²ÐµÑ Ñ response.text(), Ñогда response.json() не ÑÑабоÑаеÑ, Ñак как даннÑе Ñже бÑли обÑабоÑанÑ.
let text = await response.text(); // Ñело оÑвеÑа обÑабоÑано
let parsed = await response.json(); // оÑибка (даннÑе Ñже бÑли обÑабоÑанÑ)
Ðаголовки оÑвеÑа
Ðаголовки оÑвеÑа Ñ
ÑанÑÑÑÑ Ð² поÑ
ожем на Map обÑекÑе response.headers.
ÐÑо не ÑовÑем Map, но Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ иÑполÑзоваÑÑ Ñакие же меÑодÑ, как Ñ Map, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð»ÑÑиÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾Ðº по его имени или пеÑебÑаÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¸ в Ñикле:
let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits');
// полÑÑиÑÑ Ð¾Ð´Ð¸Ð½ заголовок
alert(response.headers.get('Content-Type')); // application/json; charset=utf-8
// пеÑебÑаÑÑ Ð²Ñе заголовки
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 меÑод, напÑимеÑPOST,bodyâ Ñело запÑоÑа, одно из ÑпиÑка:- ÑÑÑока (напÑимеÑ, в ÑоÑмаÑе JSON),
- обÑекÑ
FormDataÐ´Ð»Ñ Ð¾ÑпÑавки даннÑÑ ÐºÐ°Ðºform/multipart, 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 Ð´Ð»Ñ Ð¾ÑпÑавки вмеÑÑо ÑÑого application/json, пÑавилÑнÑй Content-Type Ð´Ð»Ñ JSON.
ÐÑпÑавка изобÑажениÑ
ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ оÑпÑавиÑÑ Ð±Ð¸Ð½Ð°ÑнÑе даннÑе пÑи помоÑи fetch, иÑполÑзÑÑ Ð¾Ð±ÑекÑÑ Blob или BufferSource.
Ð ÑÑом пÑимеÑе еÑÑÑ ÑÐ»ÐµÐ¼ÐµÐ½Ñ <canvas>, на коÑоÑом Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ ÑиÑоваÑÑ Ð´Ð²Ð¸Ð¶ÐµÐ½Ð¸ÐµÐ¼ мÑÑи. ÐÑи нажаÑии на ÐºÐ½Ð¾Ð¿ÐºÑ Â«ÐÑпÑавиÑÑ» изобÑажение оÑпÑавлÑеÑÑÑ Ð½Ð° ÑеÑвеÑ:
<body style="margin:0">
<canvas id="canvasElem" width="100" height="80" style="border:1px solid"></canvas>
<input type="button" value="ÐÑпÑавиÑÑ" 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
});
// ÑеÑÐ²ÐµÑ Ð¾ÑвеÑÐ¸Ñ Ð¿Ð¾Ð´ÑвеÑждением и ÑазмеÑом изобÑажениÑ
let result = await response.json();
alert(result.message);
}
</script>
</body>
ÐамеÑим, ÑÑо здеÑÑ Ð½Ð°Ð¼ не нÑжно вÑÑÑнÑÑ ÑÑÑанавливаÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾Ðº Content-Type, поÑÐ¾Ð¼Ñ ÑÑо обÑÐµÐºÑ Blob Ð¸Ð¼ÐµÐµÑ Ð²ÑÑÑоеннÑй Ñип (image/png, заданнÑй в toBlob). ÐÑи оÑпÑавке обÑекÑов 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 ÑоÑÑÐ¾Ð¸Ñ Ð¸Ð· двÑÑ
опеÑаÑоÑов await:
let response = await fetch(url, options); // завеÑÑаеÑÑÑ Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ°Ð¼Ð¸ оÑвеÑа
let result = await response.json(); // ÑиÑаÑÑ Ñело оÑвеÑа в ÑоÑмаÑе JSON
Ðли, без await:
fetch(url, options)
.then(response => response.json())
.then(result => /* обÑабаÑÑваем ÑезÑлÑÑÐ°Ñ */)
ÐаÑамеÑÑÑ Ð¾ÑвеÑа:
response.statusâ HTTP-код оÑвеÑа,response.okâtrue, еÑли ÑÑаÑÑÑ Ð¾ÑвеÑа в диапазоне 200-299.response.headersâ Ð¿Ð¾Ñ Ð¾Ð¶Ð¸Ð¹ наMapобÑÐµÐºÑ Ñ HTTP-заголовками.
ÐеÑÐ¾Ð´Ñ Ð´Ð»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ Ñела оÑвеÑа:
response.text()â возвÑаÑÐ°ÐµÑ Ð¾ÑÐ²ÐµÑ ÐºÐ°Ðº обÑÑнÑй ÑекÑÑ,response.json()â декодиÑÑÐµÑ Ð¾ÑÐ²ÐµÑ Ð² ÑоÑмаÑе JSON,response.formData()â возвÑаÑÐ°ÐµÑ Ð¾ÑÐ²ÐµÑ ÐºÐ°Ðº обÑÐµÐºÑ FormData (кодиÑовка form/multipart, Ñм. ÑледÑÑÑÑÑ Ð³Ð»Ð°Ð²Ñ),response.blob()â возвÑаÑÐ°ÐµÑ Ð¾Ð±ÑÐµÐºÑ ÐºÐ°Ðº Blob (бинаÑнÑе даннÑе Ñ Ñипом),response.arrayBuffer()â возвÑаÑÐ°ÐµÑ Ð¾ÑÐ²ÐµÑ ÐºÐ°Ðº ArrayBuffer (низкоÑÑовневÑе бинаÑнÑе даннÑе),
ÐпÑии fetch, коÑоÑÑе Ð¼Ñ Ð¸Ð·ÑÑили на даннÑй моменÑ:
methodâ HTTP-меÑод,headersâ обÑÐµÐºÑ Ñ Ð·Ð°Ð¿ÑаÑиваемÑми заголовками (не вÑе заголовки ÑазÑеÑенÑ),bodyâ даннÑе Ð´Ð»Ñ Ð¾ÑпÑавки (Ñело запÑоÑа) в виде ÑекÑÑа,FormData,BufferSource,BlobилиUrlSearchParams.
Ð ÑледÑÑÑиÑ
главаÑ
Ð¼Ñ ÑаÑÑмоÑÑим болÑÑе паÑамеÑÑов и ваÑианÑов иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ fetch.
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)