Skip to content

Instantly share code, notes, and snippets.

@zazaulola
Last active December 3, 2021 17:50
Show Gist options
  • Save zazaulola/be432ea00bddffcdd908f9d331ef5ab8 to your computer and use it in GitHub Desktop.
Save zazaulola/be432ea00bddffcdd908f9d331ef5ab8 to your computer and use it in GitHub Desktop.
Ajax via XMLHTTPRequest
/** @format */
/**
* @interface
* @name RequestParams
* @property {string} url адрес отправки
* @property {string} method метод
* @property {string} responseType
* @property {array} data
* @property {object} headers
* @property {function} uploadProgress
* @property {function} downloadProgress
*/
/**
* @interface
* @name ResponseParams
* @property {*} status
* @property {*} headers
* @property {*} data
*/
/**
* Отправляет Ajax запрос на сервер
* @param {RequestParams} requestParams параметры запроса
* @returns {{req: XMLHTTPRequest, res: ResponseParams, err: Error}}
*/
function ajax({ url, method, responseType, data, headers, uploadProgress, downloadProgress }) {
return new Promise((resolve, reject) => {
/* Создаем запрос */
const req = new XMLHttpRequest();
/* Сразу определим результат */
const res = { headers: [], status: 0, data };
/* Метод может быть один из:
'GET','POST','PUT','DELETE','OPTIONS'
*/
/* Открываем запрос */
req.open(method || 'GET', url);
/* устанавливаем тип ответа. Возможные варианты:
'', 'text', 'json', 'blob', 'arraybuffer', 'document' */
if (responseType) {
Object.assign(req, { responseType });
}
/* устанавливаем обработчик прогресса отправки */
if (uploadProgress) {
req.upload.onprogress = uploadProgress;
}
/* устанавливаем обработчик прогресса загрузки */
if (downloadProgress) {
req.onprogress = downloadProgress;
}
/* устанавливаем заголовки запроса */
if (headers) {
Object.entries(headers).forEach(([name, value]) => {
/* Возможные заголовки запроса:
`Accept`
`Accept-Language`
`Content-Language`
`Content-Type`
Запрещены заголовки:
`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` */
/* Если значение в виде массива */
if (Array.isArray(value)) {
/* Отправим заголовок несколько раз */
value.forEach(item => {
req.setRequestHeader(name, item);
});
} else {
req.setRequestHeader(name, value);
}
});
}
/* Обработка события смены состояния */
req.onreadystatechange = () => {
/* Если заголовки ответа уже получены */
if (this.readyState == this.HEADERS_RECEIVED) {
// Получаем заголовки ответа в raw-форме
var headers = req.getAllResponseHeaders();
/* Обработка заголовков до индивидуального заголовка
Возможные заголовки ответа:
`Cache-Control`
`Content-Language`
`Content-Length`
`Content-Type`
`Expires`
`Last-Modified`
`Pragma`
Указаные ниже заголовки в этот список не попадут:
`Set-Cookie`
`Set-Cookie2`
*/
headers
.trim()
.split(/[\r\n]+/)
.forEach(function (line) {
// Первое двоеточие отделяет ключ от значения
var parts = line.split(': ');
var key = parts.shift();
// Последующие двоеточия могут участвовать в значении заголовка
var value = parts.join(': ');
// Если заголовок с таким ключем уже есть
res.headers[key] =
key in res.headers
? // то объединяем в массив
[res.headers[key], value].flat()
: value;
});
}
};
// Отсылаем запрос
req.send(...(data ? [data] : []));
// Этот код сработает после того, как мы получим ответ сервера
req.onload = () => {
res.status = req.status;
res.data = req.response;
if (~~(req.status / 100) != 2) {
const err = new Error('Response status is ' + req.status);
// анализируем HTTP-статус ответа, если статус не 200, то произошла ошибка
// Например, 404: Not Found
reject({ req, res, err });
} else {
// если всё прошло гладко, выводим результат
// res -- это ответ сервера
resolve({ req, res, err: null });
}
};
// Обработчик ошибки запроса
req.onerror = err => {
reject({ req, res, err });
};
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment