Baseline Widely available *
ÐÑо инÑÑÑÑкÑÐ¸Ñ Ð¿Ð¾ иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ XMLHttpRequest
Ð´Ð»Ñ Ð¾Ð±Ð¼ÐµÐ½Ð° инÑоÑмаÑией Ð¼ÐµÐ¶Ð´Ñ ÑайÑом и ÑеÑвеÑом по HTTP-пÑоÑоколÑ.
ÐÑ ÑазбеÑÑм как ÑаÑÑÑе пÑимеÑÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ XMLHttpRequest
, Ñак и более Ñедкие.
ÐÐ»Ñ Ð¾ÑпÑавки HTTP-запÑоÑа нÑжно ÑоздаÑÑ XMLHttpRequest
-обÑекÑ, ÑказаÑÑ URL и оÑпÑавиÑÑ Ð·Ð°Ð¿ÑоÑ. Ð ÑезÑлÑÑаÑе запÑоÑа Ð¼Ñ Ð¿Ð¾Ð»ÑÑим Ð¾Ñ ÑеÑвеÑа обÑÐµÐºÑ Ñ Ð¿Ð¾Ð´Ñобной инÑоÑмаÑией, вÑоде Ñела оÑвеÑа и HTTP-ÑÑаÑÑÑа.
function reqListener() {
console.log(this.responseText);
}
const req = new XMLHttpRequest();
req.addEventListener("load", reqListener);
req.open("GET", "http://www.example.org/example.txt");
req.send();
Ð¢Ð¸Ð¿Ñ Ð·Ð°Ð¿ÑоÑов
ÐапÑоÑ, ÑделаннÑй поÑÑедÑÑвом XMLHttpRequest
, Ð¼Ð¾Ð¶ÐµÑ Ð·Ð°Ð³ÑÑжаÑÑ Ð´Ð°Ð½Ð½Ñе ÑинÑ
Ñонно или аÑинÑ
Ñонно. Тип запÑоÑа опÑеделÑеÑÑÑ Ð¾Ð¿ÑионалÑнÑм async
аÑгÑменÑом (ÑÑеÑий по ÑÑÑÑÑ) меÑода XMLHttpRequest.open()
. ÐÑли он Ñавен true
или не задан, запÑÐ¾Ñ Ð²ÑполниÑÑÑ Ð°ÑинÑ
Ñонно, в пÑоÑивном ÑлÑÑае â ÑинÑ
Ñонно.
Ð Ñем ÑазниÑа Ð¼ÐµÐ¶Ð´Ñ Ð´Ð²ÑÐ¼Ñ Ñипами запÑоÑов, а Ñак же пÑимеÑÑ Ð¸ÑполÑзованиÑ, Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе найÑи в ÑÑаÑÑе Ñ Ð¿Ð¾Ð´ÑобнÑм опиÑанием ÑÐ¸Ð½Ñ ÑоннÑÑ Ð¸ аÑÐ¸Ð½Ñ ÑоннÑÑ Ð·Ð°Ð¿ÑоÑов. Ðо возможноÑÑи избегайÑе ÑÐ¸Ð½Ñ ÑоннÑÑ Ð·Ð°Ð¿ÑоÑов, они блокиÑÑÑÑ Ð²Ð·Ð°Ð¸Ð¼Ð¾Ð´ÐµÐ¹ÑÑвие полÑзоваÑÐµÐ»Ñ Ñ ÑайÑом.
ÐбÑабоÑка запÑоÑовÐбÑаÑиÑе внимание: Ðазвание
XMLHttpRequest
не ознаÑаеÑ, ÑÑо Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе пеÑедаваÑÑ ÑолÑко XML докÑменÑÑ. "XML" в названии оÑÑалÑÑ Ð¸Ð· вÑемÑн, когда оÑновнÑм ÑоÑмаÑом Ð´Ð»Ñ Ð¾Ð±Ð¼ÐµÐ½Ð° инÑоÑмаÑией бÑл XML.
ÐонÑÑÑÑкÑоÑом XMLHttpRequest()
опÑÐµÐ´ÐµÐ»ÐµÐ½Ñ Ð½ÐµÑколÑко Ñипов оÑвеÑа. РоÑвеÑе ÑодеÑжиÑÑÑ Ð²Ð°Ð¶Ð½Ð°Ñ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾ ÑÑаÑÑÑе запÑоÑа. ÐÑи Ñказании некоÑоÑÑÑ
Ñипов оÑвеÑа могÑÑ Ð¿Ð¾ÑÑебоваÑÑÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑе дейÑÑÐ²Ð¸Ñ Ð´Ð»Ñ Ð¾Ð±ÑабоÑки и полÑÑÐµÐ½Ð¸Ñ ÑезÑлÑÑаÑа, ÑаÑÑмоÑÑим ÑÑи ÑлÑÑаи.
ÐÑли Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ XMLHttpRequest
загÑÑзиÑÑ XML-докÑменÑ, в ÑвойÑÑве responseXML
бÑÐ´ÐµÑ DOM-обÑекÑ, ÑодеÑжаÑий ÑаÑпаÑÑеннÑй XML-докÑменÑ, ÑабоÑаÑÑ Ð½Ð°Ð¿ÑÑмÑÑ Ñ ÐºÐ¾ÑоÑÑм бÑÐ´ÐµÑ Ñложно. ÐÑÑÑ ÑеÑÑÑе оÑновнÑÑ
ÑпоÑоба анализа ÑÑого докÑменÑа:
XMLSerializer
Ð´Ð»Ñ ÑеÑиализаÑии DOM-деÑева в ÑÑÑокÑ.RegExp
, еÑли вам заÑанее извеÑÑна ÑÑÑÑкÑÑÑа докÑменÑа. Ðозможно, поÑÑебÑеÑÑÑ ÑдалиÑÑ Ð¿ÐµÑеноÑÑ ÑÑÑок из докÑменÑа или ÑÑиÑÑваÑÑ Ð¸Ñ
в RegExp
. Ðднако, ÑÑÐ¾Ñ ÑпоÑоб ÑÑÐ¾Ð¸Ñ Ð¸ÑполÑзоваÑÑ ÑолÑко в кÑайнем ÑлÑÑае, Ð²ÐµÐ´Ñ ÐµÑли XML-докÑÐ¼ÐµÐ½Ñ Ð¸Ð·Ð¼ÐµÐ½Ð¸ÑÑÑ Ñ
оÑÑ Ð±Ñ ÑÑÑÑ-ÑÑÑÑ, Ñо ÑегÑлÑÑное вÑÑажение, ÑкоÑее вÑего, Ñже не подойдÑÑ.ÐолÑÑение HTML из responseTextÐбÑаÑиÑе внимание: ТепеÑÑ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ
responseXML
можно паÑÑиÑÑ HTML. ÐодÑобнее ÑиÑайÑе в ÑÑаÑÑе HTML в XMLHttpRequest.
ÐÑли Ð²Ñ Ð¸ÑполÑзÑеÑе XMLHttpRequest
Ð´Ð»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ ÑодеÑжимого HTML-ÑÑÑаниÑÑ, в ÑвойÑÑве responseText
бÑÐ´ÐµÑ "ÑÑÑой" HTML, ÑабоÑаÑÑ Ñ ÐºÐ¾ÑоÑÑм неÑдобно. ÐÑÑÑ ÑÑи ÑпоÑоба ÑпÑоÑÑиÑÑ ÑабоÑÑ Ñ ÑÑим "ÑÑÑÑм" HTML:
XMLHttpRequest.responseXML
, как показано в ÑÑаÑÑе HTML в XMLHttpRequest.fragment.body.innerHTML
и ÑабоÑаÑÑ Ñже Ñ ÑодеÑжимÑм ÑÑагменÑа как Ñ DOM-деÑевом.RegExp
, еÑли вам заÑанее извеÑÑна ÑÑÑÑкÑÑÑа HTML. Ðозможно, поÑÑебÑеÑÑÑ ÑдалиÑÑ Ð¿ÐµÑеноÑÑ ÑÑÑок из ÑодеÑжимого или ÑÑиÑÑваÑÑ Ð¸Ñ
в RegExp
. Ðднако, ÑÑÐ¾Ñ ÑпоÑоб ÑÑÐ¾Ð¸Ñ Ð¸ÑполÑзоваÑÑ ÑолÑко в кÑайнем ÑлÑÑае, Ð²ÐµÐ´Ñ ÐµÑли HTML измениÑÑÑ Ñ
оÑÑ Ð±Ñ ÑÑÑÑ-ÑÑÑÑ, Ñо ÑегÑлÑÑное вÑÑажение, ÑкоÑее вÑего, Ñже не подойдÑÑ.ХоÑÑ Ð¾Ð±ÑÑно XMLHttpRequest
иÑполÑзÑеÑÑÑ Ð´Ð»Ñ Ð¾ÑпÑавки и полÑÑÐµÐ½Ð¸Ñ ÑекÑÑового ÑодеÑжимого, Ñ ÐµÐ³Ð¾ помоÑÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ обмениваÑÑÑÑ Ð¸ двоиÑнÑми даннÑми. ÐÑÑÑ Ð½ÐµÑколÑко пÑовеÑеннÑÑ
ÑпоÑобов заÑÑавиÑÑ XMLHttpRequest
поÑÑлаÑÑ Ð´Ð²Ð¾Ð¸ÑнÑе даннÑе. Ðни заклÑÑаÑÑÑÑ Ð² иÑполÑзовании меÑода overrideMimeType()
.
const req = new XMLHttpRequest();
req.open("GET", url);
// пÑоÑим извлеÑÑ Ð´Ð°Ð½Ð½Ñе в виде двоиÑной ÑÑÑоки без обÑабоÑки
req.overrideMimeType("text/plain; charset=x-user-defined");
/* ... */
Ðднако, ÑÑÑеÑÑвÑÑÑ Ð¸ более ÑовÑеменнÑе ÑпоÑобÑ, Ñак как аÑÑибÑÑ responseType
ÑепеÑÑ Ð¿Ð¾Ð´Ð´ÐµÑÐ¶Ð¸Ð²Ð°ÐµÑ ÑÑд дополниÑелÑнÑÑ
Ñипов ÑодеÑжимого, ÑÑо ÑÑÑеÑÑвенно ÑпÑоÑÐ°ÐµÑ Ð¾ÑпÑÐ°Ð²ÐºÑ Ð¸ полÑÑение двоиÑнÑÑ
даннÑÑ
.
ÐÐ»Ñ Ð¿ÑимеÑа ÑаÑÑмоÑÑим ÑÑагменÑ, где иÑполÑзÑеÑÑÑ "arraybuffer
" как знаÑение responseType
Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки ÑодеÑжимого как обÑекÑа ArrayBuffer
, в коÑоÑом Ñ
ÑанÑÑÑÑ ÑÑÑÑе двоиÑнÑе даннÑе.
const req = new XMLHttpRequest();
req.onload = (e) => {
const arraybuffer = req.response; // именно response, не responseText
/* ... */
};
req.open("GET", url);
req.responseType = "arraybuffer";
req.send();
ÐолÑÑе пÑимеÑов в ÑÑаÑÑе ÐÑпÑавка и полÑÑение бинаÑнÑÑ Ð´Ð°Ð½Ð½ÑÑ .
ÐÑÑлеживание пÑогÑеÑÑа загÑÑзкиXMLHttpRequest
позволÑÐµÑ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑваÑÑÑÑ Ð½Ð° ÑазлиÑнÑе ÑобÑÑиÑ, коÑоÑÑе могÑÑ Ð¿ÑоизойÑи в пÑоÑеÑÑе обÑабоÑки запÑоÑа: пеÑиодиÑеÑкие ÑÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾ ÑоÑÑоÑнии запÑоÑа, ÑообÑÐµÐ½Ð¸Ñ Ð¾Ð± оÑибкаÑ
и Ñак далее.
СледÑÑ ÑпеÑиÑикаÑии XMLHttpRequest
поддеÑÐ¶Ð¸Ð²Ð°ÐµÑ ÑобÑÑие progress
и ÑеализÑÐµÑ Ð¸Ð½ÑеÑÑÐµÐ¹Ñ ProgressEvent
. ÐÐ»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ Ð¸Ð½ÑоÑмаÑии о пÑогÑеÑÑе загÑÑзки иÑполÑзÑйÑе ÑобÑÑиÑ:
progress
ÐаÑÑÑÐ¿Ð°ÐµÑ ÐºÐ°Ð¶Ð´Ñй Ñаз пÑи изменении обÑÑма пеÑеданнÑÑ Ð´Ð°Ð½Ð½ÑÑ .
load
ÐаÑÑÑÐ¿Ð°ÐµÑ Ð¿Ð¾ завеÑÑÐµÐ½Ð¸Ñ Ð¿ÐµÑедаÑи, когда вÑе даннÑе доÑÑÑÐ¿Ð½Ñ Ð² response
.
const req = new XMLHttpRequest();
req.addEventListener("progress", updateProgress);
req.addEventListener("load", transferComplete);
req.addEventListener("error", transferFailed);
req.addEventListener("abort", transferCanceled);
req.open();
// ...
// оÑÑлеживание пÑогÑеÑÑа пеÑедаÑи Ð¾Ñ ÑеÑвеÑа к клиенÑÑ (загÑÑзка)
function updateProgress(event) {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
// ...
} else {
// невозможно вÑÑиÑлиÑÑ ÑоÑÑоÑние загÑÑзки, Ñак как ÑÐ°Ð·Ð¼ÐµÑ Ð½ÐµÐ¸Ð·Ð²ÐµÑÑен
}
}
function transferComplete(evt) {
console.log("ÐагÑÑзка завеÑÑена.");
}
function transferFailed(evt) {
console.log("ÐÑи загÑÑзке пÑоизоÑла оÑибка.");
}
function transferCanceled(evt) {
console.log("ÐолÑзоваÑÐµÐ»Ñ Ð¾Ñменил загÑÑзкÑ.");
}
Ð 3-6 ÑÑÑокаÑ
добавлÑÑÑÑÑ Ð¾Ð±ÑабоÑÑики Ð´Ð»Ñ ÑазлиÑнÑÑ
ÑобÑÑий, пÑоиÑÑ
одÑÑиÑ
пÑи пеÑедаÑе даннÑÑ
Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ XMLHttpRequest
.
Ðажно: ÐбÑабоÑÑики нÑжно добавлÑÑÑ Ð´Ð¾ вÑзова меÑода
open()
. РпÑоÑивном ÑлÑÑаеprogress
-ÑобÑÑÐ¸Ñ Ð½Ðµ бÑдÑÑ Ð¾Ð±ÑабоÑанÑ.
ÐбÑабоÑÑик ÑобÑÑÐ¸Ñ progress
, пÑедÑÑавленнÑй ÑÑнкÑией updateProgress()
в ÑÑом пÑимеÑе, полÑÑÐ°ÐµÑ ÐºÐ¾Ð»Ð¸ÑеÑÑво байÑ, коÑоÑое должно бÑÑÑ Ð¿ÐµÑедано, и колиÑеÑÑво Ñже пеÑеданнÑÑ
Ð±Ð°Ð¹Ñ Ð² полÑÑ
total
и loaded.
Ðо еÑли длина ÑообÑÐµÐ½Ð¸Ñ Ð½ÐµÐ¸Ð·Ð²ÐµÑÑна, поле lengthComputable
бÑÐ´ÐµÑ Ñавно false
.
СобÑÑÐ¸Ñ Ð¾ Ñ
оде вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐµÑÑÑ ÐºÐ°Ðº Ñ Ð²Ñ
одÑÑиÑ
, Ñак и Ñ Ð¸ÑÑ
одÑÑиÑ
пеÑедаÑ. ÐбÑабоÑÑики ÑобÑÑий вÑ
одÑÑиÑ
пеÑÐµÐ´Ð°Ñ Ð·Ð°Ð´Ð°ÑÑÑÑ Ð´Ð»Ñ Ð¾Ð±ÑекÑа XMLHttpRequest
, как в пÑимеÑе вÑÑе, а Ð´Ð»Ñ Ð¸ÑÑ
одÑÑиÑ
â на XMLHttpRequest.upload
:
const req = new XMLHttpRequest();
req.upload.addEventListener("progress", updateProgress);
req.upload.addEventListener("load", transferComplete);
req.upload.addEventListener("error", transferFailed);
req.upload.addEventListener("abort", transferCanceled);
req.open();
ÐбÑаÑиÑе внимание: оÑÑлеживание пÑогÑеÑÑа недоÑÑÑпно Ð´Ð»Ñ Ð¿ÑоÑокола
file:
.
СобÑÑÐ¸Ñ Ð¾ Ñ
оде вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð½Ð°ÑÑÑпаÑÑ Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ полÑÑенного пакеÑа даннÑÑ
, вклÑÑÐ°Ñ Ð¿Ð¾Ñледний, поÑÑÐ¾Ð¼Ñ Ð² ÑлÑÑае, когда поÑледний Ð¿Ð°ÐºÐµÑ Ð¿Ð¾Ð»ÑÑен и Ñоединение закÑÑÑо, ÑобÑÑие progress
вÑÑ Ñавно наÑÑÑпиÑ. ÐÑо позволÑÐµÑ Ð½Ð°Ð¼ оÑÑлеживаÑÑ Ð¿ÑогÑеÑÑ, добавлÑÑ Ð¾Ð±ÑабоÑÑик ÑолÑко Ð´Ð»Ñ progress
-ÑобÑÑиÑ.
Также можно обÑабоÑаÑÑ Ð²Ñе ÑÑи ÑобÑÑиÑ, завеÑÑаÑÑие загÑÑÐ·ÐºÑ (abort
, load
, or error
) ÑеÑез ÑобÑÑие loadend
:
req.addEventListener("loadend", loadEnd);
function loadEnd(e) {
console.log("ÐеÑедаÑа даннÑÑ
завеÑÑена (но Ð¼Ñ Ð½Ðµ знаем, ÑÑпеÑно ли).");
}
ÐамеÑÑÑе, ÑÑо ÑобÑÑие loadend
никак не ÑообÑаеÑ, ÑÑо вÑзвало ÐºÐ¾Ð½ÐµÑ Ð¿ÐµÑедаÑи. ÐпÑоÑем, ÑÑо никак не меÑÐ°ÐµÑ Ð¸ÑполÑзоваÑÑ ÐµÐ³Ð¾, еÑли нÑжно ÑделаÑÑ ÑÑо-Ñо вне завиÑимоÑÑи Ð¾Ñ Ð¿ÑиÑинÑ.
ÐÑÑÑ Ð´Ð²Ð° ÑпоÑоба пеÑедаÑÑ Ð´Ð°Ð½Ð½Ñе ÑоÑм Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ XMLHttpRequest
:
FormData
API.FormData API â ÑамÑй пÑоÑÑой и бÑÑÑÑÑй ÑпоÑоб, но даннÑе, полÑÑеннÑе Ñ ÐµÐ³Ð¾ помоÑÑÑ, нелÑÐ·Ñ Ð¿ÑевÑаÑиÑÑ Ð² ÑÑÑÐ¾ÐºÑ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ JSON.stringify. ÐÑполÑзование ÑолÑко XHR Ñложнее, но ÑÑÐ¾Ñ ÑпоÑоб ÑамÑй гибкий и моÑнÑй.
ÐÑполÑзÑÑ ÑолÑкоXMLHttpRequest
ÐÑпÑавка ÑоÑÐ¼Ñ Ð±ÐµÐ· FormData API в болÑÑинÑÑве ÑлÑÑаев не ÑÑебÑÐµÑ Ð´ÑÑгиÑ
API. ÐдинÑÑвенное иÑклÑÑение, еÑли вам нÑжно оÑпÑавиÑÑ Ð¾Ð´Ð¸Ð½ или неÑколÑко Ñайлов, Ñогда пÑидÑÑÑÑ Ð¸ÑполÑзоваÑÑ FileReader
API.
HTML-ÑоÑÐ¼Ñ <form>
можно оÑпÑавиÑÑ ÑеÑÑÑÑÐ¼Ñ ÑпоÑобами:
POST
и ÑÑÑановиÑÑ Ð°ÑÑибÑÑ enctype
в знаÑении application/x-www-form-urlencoded
(ÑпоÑоб по ÑмолÑаниÑ);POST
и ÑÑÑановиÑÑ Ð°ÑÑибÑÑ enctype
в знаÑении text/plain
;POST
и ÑÑÑановиÑÑ Ð°ÑÑибÑÑ enctype
в знаÑении multipart/form-data
;GET
(в ÑÑом ÑлÑÑае аÑÑибÑÑ enctype
бÑÐ´ÐµÑ Ð¿ÑоигноÑиÑован).РаÑÑмоÑÑим оÑпÑÐ°Ð²ÐºÑ ÑоÑÐ¼Ñ Ñ Ð´Ð²ÑÐ¼Ñ Ð¿Ð¾Ð»Ñми: foo
и baz
. ÐÑли иÑполÑзоваÑÑ Ð¼ÐµÑод POST
, ÑеÑÐ²ÐµÑ Ð¿Ð¾Ð»ÑÑÐ¸Ñ ÑÑÑокÑ, поÑ
ожÑÑ Ð½Ð° Ð¾Ð´Ð½Ñ Ð¸Ð· показаннÑÑ
ниже, в завиÑимоÑÑи Ð¾Ñ Ñипа кодиÑованиÑ, коÑоÑÑй Ð²Ñ Ð¸ÑполÑзÑеÑе:
ÐеÑод: POST
; Ñип кодиÑованиÑ: application/x-www-form-urlencoded
(по ÑмолÑаниÑ):
Content-Type: application/x-www-form-urlencoded foo=bar&baz=The+first+line.%0D%0AThe+second+line.%0D%0A
ÐеÑод: POST
; Ñип кодиÑованиÑ: text/plain
:
Content-Type: text/plain foo=bar baz=The first line. The second line.
ÐеÑод: POST
; Ñип кодиÑованиÑ: multipart/form-data
:
Content-Type: multipart/form-data; boundary=---------------------------314911788813839 -----------------------------314911788813839 Content-Disposition: form-data; name="foo" bar -----------------------------314911788813839 Content-Disposition: form-data; name="baz" The first line. The second line. -----------------------------314911788813839--
РеÑли Ð²Ñ ÑеÑиÑе иÑполÑзоваÑÑ Ð¼ÐµÑод GET
, к адÑеÑÑ ÑоÑÐ¼Ñ Ð±ÑÐ´ÐµÑ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð° ÑÑÑока вида:
?foo=bar&baz=The%20first%20line.%0AThe%20second%20line.ÐеболÑÑой клаÑÑиÑеÑкий ÑÑеймвоÑк
ÐÑÑ ÑÑо возможно благодаÑÑ Ð±ÑаÑзеÑÑ Ð¸ ÑÐµÐ³Ñ <form>
. Ðо еÑли вам ÑÑебÑеÑÑÑ Ð²ÑполниÑÑ Ð²Ñе опеÑаÑии ÑолÑко Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ JavaScript, вам пÑидÑÑÑÑ Ð¿ÑоинÑÑÑÑкÑиÑоваÑÑ Ð¸Ð½ÑеÑпÑеÑаÑÐ¾Ñ Ð¾Ð±Ð¾ вÑеÑ
вÑполнÑемÑÑ
опеÑаÑиÑÑ
. ÐÑпÑавка ÑоÑÐ¼Ñ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ ÑиÑÑого XHR ÑлиÑком Ñложна, ÑÑÐ¾Ð±Ñ ÑаÑÑказаÑÑ Ð²Ð°Ð¼ о ней во вÑеÑ
деÑалÑÑ
. ÐоÑÑÐ¾Ð¼Ñ Ð¼Ñ ÑеÑили опÑбликоваÑÑ Ð·Ð´ÐµÑÑ ÑелÑй (пÑÑÑÑ Ð¸ ÑÑебнÑй) ÑÑеймвоÑк, коÑоÑÑй поддеÑÐ¶Ð¸Ð²Ð°ÐµÑ Ð²Ñе ÑеÑÑÑе ÑпоÑоба оÑпÑавки и даже загÑÑÐ·ÐºÑ Ñайлов:
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Sending forms with pure AJAX – MDN</title>
<script>
"use strict";
// :: XHR Form Submit Framework ::
//
// https://developer.mozilla.org/ru/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest
//
// This framework is released under the GNU Public License, version 3 or later.
// https://www.gnu.org/licenses/gpl-3.0-standalone.html
//
// Syntax:
//
// XHRSubmit(HTMLFormElement);
const XHRSubmit = (function () {
function xhrSuccess() {
console.log(this.responseText);
// you can get the serialized data through the "submittedData" custom property:
// console.log(JSON.stringify(this.submittedData));
}
function submitData(data) {
const req = new XMLHttpRequest();
req.submittedData = data;
req.onload = xhrSuccess;
if (data.technique === 0) {
// method is GET
req.open(
"get",
data.receiver.replace(
/(?:\?.*)?$/,
data.segments.length > 0 ? `?${data.segments.join("&")}` : "",
),
true,
);
req.send(null);
} else {
// method is POST
req.open("post", data.receiver, true);
if (data.technique === 3) {
// enctype is multipart/form-data
const boundary =
"---------------------------" + Date.now().toString(16);
req.setRequestHeader(
"Content-Type",
`multipart\/form-data; boundary=${boundary}`,
);
req.sendAsBinary(
`--${boundary}\r\n` +
data.segments.join(`--${boundary}\r\n`) +
`--${boundary}--\r\n`,
);
} else {
// enctype is application/x-www-form-urlencoded or text/plain
req.setRequestHeader("Content-Type", data.contentType);
req.send(data.segments.join(data.technique === 2 ? "\r\n" : "&"));
}
}
}
function processStatus(data) {
if (data.status > 0) {
return;
}
// the form is now totally serialized! do something before sending it to the serverâ¦
// doSomething(data);
// console.log("XHRSubmit - The form is now serialized. Submitting...");
submitData(data);
}
function pushSegment(segment) {
this.owner.segments[this.segmentIdx] +=
segment.target.result + "\r\n";
this.owner.status--;
processStatus(this.owner);
}
function plainEscape(text) {
// How should I treat a text/plain form encoding?
// What characters are not allowed? this is what I supposeâ¦:
// "4\3\7 - Einstein said E=mc2" ----> "4\\3\\7\ -\ Einstein\ said\ E\=mc2"
return text.replace(/[\s\=\\]/g, "\\$&");
}
function SubmitRequest(target) {
const isPost = target.method.toLowerCase() === "post";
this.contentType =
isPost && target.enctype
? target.enctype
: "application\/x-www-form-urlencoded";
this.technique = isPost
? this.contentType === "multipart\/form-data"
? 3
: this.contentType === "text\/plain"
? 2
: 1
: 0;
this.receiver = target.action;
this.status = 0;
this.segments = [];
const filter = this.technique === 2 ? plainEscape : escape;
for (const field of target.elements) {
if (!field.hasAttribute("name")) {
continue;
}
const fieldType =
field.nodeName.toUpperCase() === "INPUT" &&
field.hasAttribute("type")
? field.getAttribute("type").toUpperCase()
: "TEXT";
if (fieldType === "FILE" && field.files.length > 0) {
if (this.technique === 3) {
// enctype is multipart/form-data
for (const file of field.files) {
const segmReq = new FileReader();
// Custom properties:
segmReq.segmentIdx = this.segments.length;
segmReq.owner = this;
segmReq.onload = pushSegment;
this.segments.push(
'Content-Disposition: form-data; name="' +
field.name +
'"; filename="' +
file.name +
'"\r\nContent-Type: ' +
file.type +
"\r\n\r\n",
);
this.status++;
segmReq.readAsBinaryString(file);
}
} else {
// enctype is application/x-www-form-urlencoded or text/plain or
// method is GET: files will not be sent!
for (const file of field.files) {
this.segments.push(
`${filter(field.name)}=${filter(file.name)}`,
);
}
}
} else if (
(fieldType !== "RADIO" && fieldType !== "CHECKBOX") ||
field.checked
) {
// NOTE: this will submit _all_ submit buttons. Detecting the correct one is non-trivial.
// field type is not FILE or is FILE but is empty.
if (this.technique === 3) {
// enctype is multipart/form-data
this.segments.push(
`Content-Disposition: form-data; name="${field.name}"\r\n\r\n${field.value}\r\n`,
);
} else {
// enctype is application/x-www-form-urlencoded or text/plain or method is GET
this.segments.push(
`${filter(field.name)}=${filter(field.value)}`,
);
}
}
}
processStatus(this);
}
return (formElement) => {
if (!formeElement.action) {
return;
}
new SubmitRequest(formElement);
};
})();
</script>
</head>
<body>
<h1>Sending forms with XHR</h1>
<h2>Using the GET method</h2>
<form
action="register.php"
method="get"
onsubmit="AJAXSubmit(this); return false;">
<fieldset>
<legend>Registration example</legend>
<p>
<label>First name: <input type="text" name="firstname" /></label
><br />
<label>Last name: <input type="text" name="lastname" /></label>
</p>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</form>
<h2>Using the POST method</h2>
<h3>Enctype: application/x-www-form-urlencoded (default)</h3>
<form
action="register.php"
method="post"
onsubmit="AJAXSubmit(this); return false;">
<fieldset>
<legend>Registration example</legend>
<p>
<label>First name: <input type="text" name="firstname" /></label>
<br />
<label>Last name: <input type="text" name="lastname" /></label>
</p>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</form>
<h3>Enctype: text/plain</h3>
<form
action="register.php"
method="post"
enctype="text/plain"
onsubmit="AJAXSubmit(this); return false;">
<fieldset>
<legend>Registration example</legend>
<p>
<label
>Your name:
<input type="text" name="user" />
</label>
</p>
<p>
<label
>Your message:<br />
<textarea name="message" cols="40" rows="8"></textarea>
</label>
</p>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</form>
<h3>Enctype: multipart/form-data</h3>
<form
action="register.php"
method="post"
enctype="multipart/form-data"
onsubmit="AJAXSubmit(this); return false;">
<fieldset>
<legend>Upload example</legend>
<p>
<label>First name: <input type="text" name="firstname" /></label
><br />
<label>Last name: <input type="text" name="lastname" /></label><br />
Sex:
<input id="sex_male" type="radio" name="sex" value="male" />
<label for="sex_male">Male</label>
<input id="sex_female" type="radio" name="sex" value="female" />
<label for="sex_female">Female</label><br />
Password: <input type="password" name="secret" /><br />
<label
>What do you prefer:
<select name="image_type">
<option>Books</option>
<option>Cinema</option>
<option>TV</option>
</select>
</label>
</p>
<p>
<label
>Post your photos:
<input type="file" multiple name="photos[]" />
</label>
</p>
<p>
<input
id="vehicle_bike"
type="checkbox"
name="vehicle[]"
value="Bike" />
<label for="vehicle_bike">I have a bike</label><br />
<input
id="vehicle_car"
type="checkbox"
name="vehicle[]"
value="Car" />
<label for="vehicle_car">I have a car</label>
</p>
<p>
<label
>Describe yourself:<br />
<textarea name="description" cols="50" rows="8"></textarea>
</label>
</p>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</form>
</body>
</html>
ЧÑÐ¾Ð±Ñ Ð²Ð¾ÑполÑзоваÑÑÑÑ ÑÑеймвоÑком, ÑоздайÑе ÑÑÑаниÑÑ Ñ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸ÐµÐ¼ register.php (и ÑкажиÑе его в аÑÑибÑÑе action
одной из ÑоÑм в пÑимеÑе) Ñ Ð¼Ð¸Ð½Ð¸Ð¼Ð°Ð»ÑнÑм ÑодеÑжимÑм:
<?php
/* register.php */
header("Content-type: text/plain");
/*
NOTE: You should never use `print_r()` in production scripts, or
otherwise output client-submitted data without sanitizing it first.
Failing to sanitize can lead to cross-site scripting vulnerabilities.
*/
echo ":: data received via GET ::\n\n";
print_r($_GET);
echo "\n\n:: Data received via POST ::\n\n";
print_r($_POST);
echo "\n\n:: Data received as \"raw\" (text/plain encoding) ::\n\n";
if (isset($HTTP_RAW_POST_DATA)) { echo $HTTP_RAW_POST_DATA; }
echo "\n\n:: Files received ::\n\n";
print_r($_FILES);
>
ÐÐ»Ñ Ð°ÐºÑиваÑии вÑполниÑе код:
Ðажно: ÐÐ°Ñ ÑÑеймвоÑк иÑполÑзÑеÑ
FileReader
API Ð´Ð»Ñ Ð¿ÐµÑедаÑи Ñайлов. ÐÑо новÑй API и его невозможно иÑполÑзоваÑÑ Ð² IE9 и ниже. Ð ÑвÑзи Ñ ÑÑим, загÑÑзки ÑолÑко Ñ Ð¸ÑполÑзованием AJAX воÑпÑинимаÑÑÑÑ Ð»Ð¸ÑÑ ÐºÐ°Ðº ÑкÑпеÑименÑалÑнÑе. ÐÑли вам не ÑÑебÑеÑÑÑ Ð·Ð°Ð³ÑÑжаÑÑ Ð±Ð¸Ð½Ð°ÑнÑе ÑайлÑ, Ñо даннÑй ÑÑеймвоÑк ÑабоÑÐ°ÐµÑ Ð² болÑÑинÑÑве ÑовÑеменнÑÑ Ð±ÑаÑзеÑов.
ÐÑполÑзÑÑ FormDataÐбÑаÑиÑе внимание: ÐÑÑÑий ÑпоÑоб оÑпÑавиÑÑ Ð±Ð¸Ð½Ð°ÑнÑе даннÑе â иÑполÑзоваÑÑ
ArrayBuffers
илиBlobs
в ÑвÑзке Ñ Ð¼ÐµÑодомsend()
и меÑодомreadAsArrayBuffer()
изFileReader
API. Ðо Ñак как ÑÐµÐ»Ñ Ð½Ð°Ñего пÑимеÑа â поддеÑжка возможноÑÑи пÑедÑÑавиÑÑ ÑÑÑÑе даннÑе в виде ÑÑÑоки, Ð¼Ñ Ð¸ÑполÑзовали меÑодsendAsBinary()
в ÑвÑзке ÑreadAsBinaryString()
изFileReader
API. Таким обÑазом, пÑиведеннÑй вÑÑе код Ð¸Ð¼ÐµÐµÑ ÑмÑÑл иÑполÑзоваÑÑ ÑолÑко в Ñом ÑлÑÑае, еÑли Ð²Ñ Ð¸Ð¼ÐµÐµÑе дело Ñ Ð½ÐµÐ±Ð¾Ð»ÑÑими Ñайлами. ÐÑли Ð²Ñ Ð½Ðµ планиÑÑеÑе загÑÑжаÑÑ Ð´Ð²Ð¾Ð¸Ñное ÑодеÑжимое, вмеÑÑо ÑÑого воÑполÑзÑйÑеÑÑFormData
API.
The FormData
constructor lets you compile a set of key/value pairs to send using XMLHttpRequest
. Its primary use is in sending form data, but can also be used independently from a form in order to transmit user keyed data. The transmitted data is in the same format the form's submit()
method uses to send data, if the form's encoding type were set to "multipart/form-data". FormData objects can be utilized in a number of ways with an XMLHttpRequest
. For examples, and explanations of how one can utilize FormData with XMLHttpRequests, see the Using FormData Objects page. For didactic purposes here is a translation of the previous example transformed to use the FormData
API. Note the brevity of the code:
<!doctype html>
<html lang="en-US">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<title>Sending forms with FormData – MDN</title>
<script>
"use strict";
function xhrSuccess () {
console.log(this.responseText);
}
function XHRSubmit (formElement) {
if (!formElement.action) { return; }
const req = new XMLHttpRequest();
req.onload = xhrSuccess;
if (fFormElement.method.toLowerCase() === "post") {
req.open("post", formElement.action);
req.send(new FormData(formElement));
} else {
let search = "";
for (const field of formElement.elements) {
if (!field.hasAttribute("name")) { continue; }
const fieldType = field.nodeName.toUpperCase() === "INPUT" && oField.hasAttribute("type")
? field.getAttribute("type").toUpperCase()
: "TEXT";
if (fieldType === "FILE") {
for (const file of field.files) {
search += `&${escape(field.name)}=${escape(file.name)}`;
} else if ((fieldType !== "RADIO" && fieldType !== "CHECKBOX") || field.checked) {
search += `&${escape(field.name)}=${escape(field.value)}`;
}
}
req.open("get", formElement.action.replace(/(?:\?.*)?$/, search.replace(/^&/, "?")), true);
req.send(null);
}
}
</script>
</head>
<body>
<h1>Sending forms with FormData</h1>
<h2>Using the GET method</h2>
<form
action="register.php"
method="get"
onsubmit="AJAXSubmit(this); return false;">
<fieldset>
<legend>Registration example</legend>
<p>
First name: <input type="text" name="firstname" /><br />
Last name: <input type="text" name="lastname" />
</p>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</form>
<h2>Using the POST method</h2>
<h3>Enctype: application/x-www-form-urlencoded (default)</h3>
<form
action="register.php"
method="post"
onsubmit="AJAXSubmit(this); return false;">
<fieldset>
<legend>Registration example</legend>
<p>
First name: <input type="text" name="firstname" /><br />
Last name: <input type="text" name="lastname" />
</p>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</form>
<h3>Enctype: text/plain</h3>
<p>The text/plain encoding is not supported by the FormData API.</p>
<h3>Enctype: multipart/form-data</h3>
<form
action="register.php"
method="post"
enctype="multipart/form-data"
onsubmit="AJAXSubmit(this); return false;">
<fieldset>
<legend>Upload example</legend>
<p>
First name: <input type="text" name="firstname" /><br />
Last name: <input type="text" name="lastname" /><br />
Sex:
<input id="sex_male" type="radio" name="sex" value="male" />
<label for="sex_male">Male</label>
<input id="sex_female" type="radio" name="sex" value="female" />
<label for="sex_female">Female</label><br />
Password: <input type="password" name="secret" /><br />
What do you prefer:
<select name="image_type">
<option>Books</option>
<option>Cinema</option>
<option>TV</option>
</select>
</p>
<p>
Post your photos:
<input type="file" multiple name="photos[]" />
</p>
<p>
<input
id="vehicle_bike"
type="checkbox"
name="vehicle[]"
value="Bike" />
<label for="vehicle_bike">I have a bike</label><br />
<input
id="vehicle_car"
type="checkbox"
name="vehicle[]"
value="Car" />
<label for="vehicle_car">I have a car</label>
</p>
<p>
Describe yourself:<br />
<textarea name="description" cols="50" rows="8"></textarea>
</p>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</form>
</body>
</html>
ÐÑимеÑание: As we said, FormData
objects are not stringifiable objects. If you want to stringify a submitted data, use the previous pure-AJAX example. Note also that, although in this example there are some file
<input>
fields, when you submit a form through the FormData
API you do not need to use the FileReader
API also: files are automatically loaded and uploaded.
function getHeaderTime() {
console.log(this.getResponseHeader("Last-Modified")); // ÐаÑа вида GMTString или null
}
const req = new XMLHttpRequest();
req.open(
"HEAD", // иÑполÑзÑеÑÑÑ HEAD ÑолÑко еÑли ÑеÑÐ²ÐµÑ ÑÑебÑÐµÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¸
"yourpage.html",
);
req.onload = getHeaderTime;
req.send();
Do something when last modified date changes
Let's create two functions:
function getHeaderTime() {
const lastVisit = parseFloat(
window.localStorage.getItem(`lm_${this.filepath}`),
);
const lastModified = Date.parse(this.getResponseHeader("Last-Modified"));
if (isNaN(lastVisit) || lastModified > lastVisit) {
window.localStorage.setItem(`lm_${this.filepath}`, Date.now());
isFinite(lastVisit) && this.callback(lastModified, lastVisit);
}
}
function ifHasChanged(URL, callback) {
const req = new XMLHttpRequest();
req.open("HEAD" /* use HEAD - we only need the headers! */, URL);
req.callback = callback;
req.filepath = URL;
req.onload = getHeaderTime;
req.send();
}
And to test:
// Let's test the file "yourpage.html"
ifHasChanged("yourpage.html", function (modified, visit) {
console.log(
`The page '${this.filepath}' has been changed on ${new Date(
nModified,
).toLocaleString()}!`,
);
});
If you want to know if the current page has changed, refer to the article about document.lastModified
.
СовÑеменнÑе бÑаÑзеÑÑ Ð¿Ð¾Ð´Ð´ÐµÑживаÑÑ Ð¼ÐµÐ¶ÑайÑовÑе запÑоÑÑ Ð¿Ð¾ ÑÑандаÑÑÑ Cross-Origin Resource Sharing (CORS). ÐÐ»Ñ ÑÑого ÑеÑвеÑÑ Ð½ÐµÐ¾Ð±Ñ
одимо дополниÑелÑно ÑказÑваÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾Ðº origin
. РпÑоÑивном ÑлÑÑае, вÑбÑаÑÑваеÑÑÑ Ð¸ÑклÑÑение INVALID_ACCESS_ERR
.
ÐÐ»Ñ Ð¼ÐµÐ¶ÑайÑового Ð¾Ð±Ñ Ð¾Ð´Ð° кеÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð² ÐºÐ¾Ð½ÐµÑ URL-запÑоÑа доÑÑаÑоÑно добавиÑÑ ÑлÑÑайнÑÑ ÑÑÑÐ¾ÐºÑ Ð² GET-паÑамеÑÑÑ, Ñо еÑÑÑ ÑÑÐ°Ð·Ñ Ð¿Ð¾Ñле «?», напÑимеÑ:
http://foo.com/bar.html -> http://foo.com/bar.html?12345 http://foo.com/bar.html?foobar=baz -> http://foo.com/bar.html?foobar=baz&12345
Таким обÑазом, каждÑй новÑй запÑÐ¾Ñ Ð±ÑÐ´ÐµÑ Ð¿ÑоиÑÑ Ð¾Ð´Ð¸ÑÑ Ð¿Ð¾ Ð½Ð¾Ð²Ð¾Ð¼Ñ URL, не бÑаÑÑÑÑ Ð¸Ð· кÑÑа.
ÐвÑомаÑизиÑоваÑÑ ÑÑÐ¾Ñ Ð¿Ð¾Ð´Ñ Ð¾Ð´ можно ÑледÑÑÑим обÑазом:
const req = new XMLHttpRequest();
req.open("GET", url + (/\?/.test(url) ? "&" : "?") + new Date().getTime());
req.send(null);
ÐезопаÑноÑÑÑ
РекомендÑемÑй ÑпоÑоб ÑазÑеÑиÑÑ Ð¼ÐµÐ¶ÑайÑовÑе запÑоÑÑ - иÑполÑзоваÑÑ HTTP-заголовок Access-Control-Allow-Origin
в оÑвеÑе на XMLHttpRequest.
ÐÑли в завеÑÑение XMLHttpRequest Ð²Ñ Ð¿Ð¾Ð»ÑÑаеÑе status=0
и statusText=null
â ÑÑо ознаÑаеÑ, ÑÑо запÑÐ¾Ñ Ð½Ðµ бÑл ÑазÑеÑен к вÑполнениÑ. Ðго ÑÑаÑÑÑ Ð¾ÑÑалÑÑ UNSENT
. ЧаÑÑÐ°Ñ Ð¿ÑиÑина, ÑÑо ÑказаннÑй XMLHttpRequest
origin (во вÑÐµÐ¼Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ XMLHttpRequest) бÑл изменÑн в ÑледÑÑвии вÑзова open()
. Такое Ð¼Ð¾Ð¶ÐµÑ Ð¿ÑоизойÑи, напÑимеÑ, когда еÑÑÑ XMLHttpRequest, коÑоÑÑй запÑÑкаеÑÑÑ Ð¿Ñи ÑобÑÑии onunload окна. XMLHttpRequest ÑоздаеÑÑÑ, когда окно, коÑоÑое должно бÑÑÑ Ð·Ð°ÐºÑÑÑо, вÑÑ ÐµÑÑ ÑÑÑеÑÑвÑеÑ, но оÑпÑавка запÑоÑа (дÑÑгими Ñловами, вÑзов open()
) пÑоиÑÑ
одиÑ, когда ÑÑо окно Ñже поÑеÑÑло Ñвой ÑокÑÑ, а дÑÑгое â полÑÑило. Ðаиболее ÑÑÑекÑивнÑй ÑпоÑоб избежаÑÑ ÑÑой пÑÐ¾Ð±Ð»ÐµÐ¼Ñ - ÑÑÑановиÑÑ ÑлÑÑаÑÐµÐ»Ñ Ð½Ð° ÑобÑÑие нового окна DOMActivate
, коÑоÑое ÑÑÑанавливаеÑÑÑ, как ÑолÑко Ñ Ð·Ð°ÐºÑÑÑого окна ÑÑабаÑÑÐ²Ð°ÐµÑ ÑобÑÑие unload
.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4