Глубокое понимание XMLHttpRequest

Ajax
Глубокое понимание XMLHttpRequest

Во-первых, процесс разработки XMLHttpRequest.

AjaxЯдром технологии являетсяXMLHttpRequestобъект. Мы используемXMLHttpRequestобъект для отправкиAjaxпросить. Это функция, впервые представленная Microsoft, и с тех пор другие поставщики браузеров предлагают такую ​​же реализацию.

XMLHttpRequestполучил широкое распространение, а позднееW3CОн был стандартизирован, предложенныйXMLHttpRequestстандарт.XMLHttpRequestСтандарт делится наLevel 1а такжеLevel 2.

Не все браузеры полностью реализуютXMLHttpRequest 2级спецификация, но все браузеры реализуют часть того, что в ней указано.

XMLHttpRequest Level 1Основные недостатки заключаются в следующем:

  1. Невозможно отправлять двоичные файлы (например, изображения, видео, аудио и т. д.), только текстовые данные.
  2. В процессе отправки и получения данных информация о прогрессе не может быть получена в режиме реального времени, и можно судить только о том, завершен ли он.
  3. В соответствии с политикой одного и того же источника отправка запросов между источниками невозможна.

Level 2правильноLevel 1улучшен,XMLHttpRequest Level 2Были добавлены следующие функции:

  1. Междоменные запросы могут быть отправлены, если сервер это позволяет.
  2. Поддерживает отправку и получение двоичных данных.
  3. новыйformDataОбъект, поддерживающий отправку данных формы.
  4. При отправке и получении данных можно получить информацию о ходе выполнения.
  5. Время ожидания запроса может быть установлено.

Следующая строка кода может создатьXMLHttpRequestобъект.

const xhr = new XMLHttpRequest()

Запрос совместимости:потрите newser.com/#search=XML…

Во-вторых, объект XMLHttpRequest отправляет API, связанный с запросом.

Связанный с заголовком запроса

  • Accept: Тип контента, который может обрабатывать клиент. Например:Accept: */*.
  • Accept-Charset: Тип набора символов, который может обрабатывать клиент. Например:Accept-Charset: utf8.
  • Accept-Encoding: Сжатие кодирования клиент может обрабатывать. Например:Accept-Encoding: gzip, deflate, br.
  • Accept-Language: язык, установленный в данный момент клиентом. Например:Accept-Language: zh-CN,zh;q=0.9,en;q=0.8.
  • Connection: тип соединения между клиентом и сервером. Например:Connection: keep-alive.
  • Cookie: все, что установлено текущей страницейCookie.
  • Host: Домен, в котором находится запрашивающая страница.
  • Referer: указывает адрес исходной страницы текущей страницы запроса, то есть доступ к текущей странице осуществляется по ссылке на этой исходной странице.
  • User-Agent: Строка пользовательского агента клиента. Как правило, он содержит информацию о версии и модели браузера, ядра браузера и операционной системы.
  • Content-Type: клиент сообщает серверу, какой тип данных фактически отправляется. Например:Content-Type: application/x-www-form-urlencoded.

Больше ссылок:developer.Mozilla.org/this-cn/docs/…

метод open()

open()Метод используется для инициации запроса.

open()Метод принимает три параметра:

  1. первый параметрmethod: тип запроса для отправки. НапримерGET,POST,PUT,DELETEЖдать.
  2. второй параметрurl: запрошеноURL.
  3. третий параметрasync: логическое значение, указывающее, следует ли отправлять запрос асинхронно.trueОтправляйте запросы асинхронно.
const xhr = new XMLHttpRequest()
xhr.open('get', '/userInfo', true)

передачаopen()Метод фактически не отправляет запрос, а только запускает запрос на доставку.

метод отправки()

send()способ отправкиHTTPпросить.

send()Метод принимает один параметр:

  1. первый параметрdata: данные, отправленные в виде тела запроса. Если вам не нужно отправлять данные через тело запроса, вы должны передатьnull.该参数可以接收字符串、FormData,Blob,ArrayBufferи другие типы.
const xhr = new XMLHttpRequest()
xhr.send(null)

Метод setRequestHeader()

setRequestHeader()метод для установки пользовательских заголовков запросов.

setRequestHeader()Метод принимает два параметра:

  1. первый параметрheader: Имя поля заголовка.
  2. второй параметрvalue: значение поля заголовка.

Для успешной отправки заголовков запроса этот метод должен бытьopen()а такжеsend()между звонками.

const xhr = new XMLHttpRequest()
xhr.open('get', '/server', true)
xhr.setRequestHeader('MyHeader', 'MyValue')
xmlhttp.send()

свойство readyState и событие onreadystatechange

readyStateАтрибут указывает текущую активную фазу процедуры запроса/ответа. Значения свойств следующие:

  • 0 (UNSENT) Неинициализированный. еще не звонилopen()метод.
  • 1(OPENED)запускать. был названopen()Метод, но не вызываетsend()метод.
  • 2(HEADERS_RECEIVED)Отправить. был названsend()способом, но ответа пока не получил.
  • 3 (LOADING)перенимать. Получены частичные данные ответа.
  • 4 (DONE)Заканчивать. Все данные ответа получены.

если толькоreadyStateКогда значение свойства изменится, оно будет запущено один разonreadystatechangeмероприятие. Используйте это событие для обнаружения после каждого изменения состоянияreadyStateценность . Обычно толькоreadyStateзначение4процесс, и все данные готовы в это время.

const xhr = new XMLHttpRequest()
xhr.open('get', '/server', true)
xhr.onreadystatechange = function () {
  if(xhr.readyState !== 4) {
    return  
  }
  if(xhr.status >= 200 && xhr.status < 300) {
    console.log(xhr.responseText)
  }
}
xhr.send(null)

свойство timeout и событие ontimeout

timeoutСвойство указывает, сколько миллисекунд запрос должен ожидать ответа перед завершением. Срабатывает, если браузер не получил ответа в течение заданного времениontimeoutобработчик события.

const xhr = new XMLHttpRequest()
xhr.open('get', '/server', true)
//将超时设置为3秒钟
xhr.timeout = 3000 
// 请求超时后请求自动终止,会调用 ontimeout 事件处理程序
xhr.ontimeout = function(){
    console.log('请求超时了')
}
xhr.send(null)

метод overrideMimeType()

overrideMimeType()Метод может переопределить возврат, возвращаемый сервером.MIMEtype, чтобы браузер мог обрабатывать его по-разному.

Если тип данных, возвращаемый сервером,text/xml, по разным причинам браузер не может выполнить синтаксический анализ и сообщает об ошибке, а данные не могут быть получены в настоящее время. Чтобы получить исходные данные, можно положитьMIMEтип изменен наtext/plain, чтобы браузер не разбирал его автоматически, чтобы мы могли получить исходный текст.

const xhr = new XMLHttpRequest()
xhr.open('get', '/server', true)
xhr.overrideMimeType('text/plain')
xhr.send(null)

Свойство responseType

responseTypeСвойство представляет собой строку, представляющую тип данных, возвращаемых сервером. использоватьxhr.responseимущество для получения.

Это свойство доступно для записи и может быть вызваноopen()После метода,send()Значение этого свойства устанавливается перед методом, чтобы указать серверу вернуть данные указанного типа. еслиresponseTypeЗадайте пустую строку, эквивалентную значению по умолчанию.text.

responseTypeТипы форматов, которые могут быть заданы для свойств, следующие:

responseTypeстоимость имущества responseтип данных свойства иллюстрировать
"" Stringнить значение по умолчанию, эквивалентноеtext(без установкиresponseTypeВремя)
"text" Stringнить Сервер возвращает текстовые данные
"document" Documentобъект надеюсь вернутьсяXMLиспользуется при форматировании данных
"json" javaScriptобъект IE10/IE11не поддерживается
"blob" Blobобъект сервер возвращает бинарный объект
"arrayBuffer" ArrayBufferобъект сервер возвращает двоичный массив

КогдаresponseTypeПри установке определенного типа необходимо убедиться, что тип, возвращаемый сервером, совместим с типом возвращаемого значения, которое вы установили. Затем, если два типа несовместимы, данные, возвращаемые сервером, станутnull, даже если сервер возвращает данные.

установить для синхронного запросаresponseTypeброситInvalidAccessErrorисключение.

// 获取一张图片代码示例
const xhr = new XMLHttpRequest()
xhr.open('get', '/server/image.png', true)
xhr.responseType = 'blob'
xhr.onload = function(e) {
  if (xhr.status >= 200 && xhr.status < 300) {
    const blob = this.response
    // ...
  }
}
xhr.send(null)

свойство withCredentials

withCredentialsСвойство представляет собой логическое значение, указывающее, включаются ли учетные данные в запросы между источниками (cookie,HTTPАутентификация и клиентSSLдоказательство и др.). По умолчаниюfalse.

Если вам нужно пересечь доменAjaxзапрос на отправкуCookie,нужноwithCredentialsсвойство установлено наtrue. Если настроено в том же доменеxhr.withCredentials, вне зависимости от конфигурацииtrueещеfalse, эффект будет тот же.

const xhr = new XMLHttpRequest()
xhr.open('get', '/server', true)
xhr.withCredentials = true
xhr.send(null)

при настройкеwithCredentialsдляtrue, необходимо добавить в бэкэндresponseинформация заголовкаAccess-Control-Allow-Origin, и имя домена должно быть указано, а не как*. также добавитьAccess-Control-Allow-CredentialsЭтот заголовок соответствует действительности.

response.addHeader("Access-Control-Allow-Origin", "http://example.com")
response.addHeader("Access-Control-Allow-Credentials", "true")

метод abort() и событие onabort

Вызывается до получения ответаabort()метод используется для отмены асинхронного запроса. Когда запрос завершается, егоreadyStateсвойство будет установлено в0. После завершения запроса вы также должныXMLHttpRequeatОбъект разыменован.

при звонкеabort(), это вызоветonabortмероприятие.

const xhr = new XMLHttpRequest()
xhr.open('get', '/server', true)
xmlhttp.onabort = function () {
  console.log('请求被中止')
}
xmlhttp.send()
// 将会调用我们上面定义的 onabort 回调函数
xmlhttp.abort()

ПОЛУЧИТЬ запрос

Добавьте параметр строки запроса вURLв конце отправьте информацию на сервер.

GETЧеловек не может повлиять на метод кодирования параметров, что приводит к различным методам кодирования для разных браузеров, поэтому самым безопасным решением является ручное предварительное кодирование и ручное декодирование, чтобы запретить вмешательство кодирования браузера.

const xhr = new XMLHttpRequest()
// 使用encodeURIComponent()进行编码
const tempParam = encodeURIComponent('age')
const tempValue = encodeURIComponent('20')
xhr.open('get', '/server?tempParam=tempValue&money=100', true)

POST-запрос

POSTЗапрос имеет данные в качестве тела запроса (запрошенныйbody)представить. Вот четыре общихPOSTМетод запроса на отправку данных.

application/x-www-form-urlencoded

родной браузер<form>форма, если не заданаenctypeсвойства, то окончательный результат будетapplication/x-www-form-urlencodedспособ подачи данных.

multipart/form-data

При загрузке файлов из формы необходимо разрешить<form>формаenctypeравныйmultipart/form-data.

application/json

при отправкеAjaxПри запросе поставитьapplication/jsonВ качестве заголовка запроса он используется, чтобы сообщить серверу, что тело сообщения сериализовано.JSONнить.

text/xml

использоватьHTTPВ качестве транспортного протоколаXMLСпецификация удаленного вызова как кодировка.

Имитация отправки формы с помощью XMLHttpRequest

БудуContent-TypeИнформация заголовка устанавливается наapplication/x-www-form-urlencoded. можно использоватьXMLHttpRequestобъект для имитации отправки формы.

const xhr = new XMLHttpRequest()
xhr.open('post', '/server', true)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
const form = document.getElementById('myForm') 
// serialize()为表单序列化方法
xhr.send(serialize(form))

также можно использоватьXMLHttpRequest level 2изFormDataдля сериализации данных формы.

const xhr = new XMLHttpRequest()
xhr.open('post', '/server', true)
const form = document.getElementById('myForm')
const formData = new FormData(form)
formData.append("id", "123456")
xhr.send(formData)

использоватьFormDataне обязательно явноXMLHttpRequestУстановите заголовки запроса для объекта.XMLHttpRequestОбъект способен распознать тип входящих данныхFormDatainstance и настройте соответствующую информацию заголовка.

API, связанный с событием выполнения XMLHttpRequest

onloadstart

существуетXMLHttpRequestСрабатывает, когда объект начинает передавать данные, то есть вызовsend()метод(HTTPзапрос).

xhr.onloadstart = function () {
  console.log('开始发出请求...')
}

onprogress

Запускается постоянно при получении ответа.

onprogressОбработчик события получаетeventобъект, егоtargetсобственностьXMLHttpRequestобъект иeventСодержит три дополнительных свойства:loaded,totalа такжеlengthComputable.

  1. event.loaded: количество переданных данных (полученных байтов).
  2. event.total: Общий объем данных (согласноContent-LengthКоличество ожидаемых байтов определяется заголовком).
  3. event.lengthComputable: логическое значение, указывающее, доступна ли информация о ходе выполнения.

С помощью этой информации можно создатьAjaxИндикатор выполнения запроса.

const xhr = new XMLHttpRequest()
xhr.onprogress = function (event) {
    if (!event.lengthComputable) {
        return console.log('无法计算进展')
    }
    const percentComplete = event.loaded / event.total * 100
    console.log(`进度百分比:${percentComplete}%`)
}
xhr.open('post', '/server', true)
xhr.send(null)

onerror

Запускается при возникновении ошибки в запросе. Это событие запускается только при возникновении исключения на уровне сети. Для исключений на уровне приложения, таких как возвращенный ответstatusCodeда4xx, не принадлежитNetWork Error, так что не сработаетonerrorсобытие, но вызоветonloadмероприятие.

xhr.onerror = function(e) {
 console.log('数据接收出错')
}

onabort

передачаabort()метод завершения запроса.

onload

Запускается, когда запрос выполнен успешно и получены полные данные ответа.

можно использоватьonloadВместо этого можно использовать событияreadystatechangeмероприятие.因为响应接收完毕后将触发onloadсобытие, поэтому нет необходимости проверятьreadyStateхарактеристики. Срабатывает всякий раз, когда браузер получает ответ от сервера, независимо от его состояния.loadмероприятие.

const xhr = new XMLHttpRequest()
xhr.onload = function onload() {
  console.log('数据接收完毕')
  if(xhr.status >= 200 && xhr.status < 300) {
    console.log(xhr.responseText)
  }
}
xhr.open('post', '/server', true)

xhr.send(formData)

Для обеспечения нормального выполнения его необходимо вызватьopen()добавить перед методомonprogressобработчик события.

onloadend

В конце запроса (включая успех запроса и отказ запроса) или триггерerror,abortилиloadУволен после события.

xhr.onloadend = function(e) {
  console.log('请求结束,状态未知')
}

Каждый запрос запускается изloadstartНачинается событие, за которым следует одно или несколькоprogressсобытие, затем запускаетerror,abortилиloadодно из событий, которое, наконец, вызываетloadendСобытие заканчивается.

загрузить свойство

XMLHttpRequestВы можете не только отправлять запросы, но и файлы, чтоAjaxФайл загружен.

После отправки файла пройтиXMLHttpRequest.uploadСвойства могут получитьXMLHttpRequestUploadобъект. С помощью этого объекта вы можете узнать о ходе загрузки. Схема реализации заключается в прослушивании различных событий этого объекта:onloadstart,onprogress,onabort,onerror,onload,ontimeout,onloadend.

Когда файл загружен, даuploadназначение атрибутаprogressФункция прослушивания событий для получения информации о ходе загрузки.

const xhr = new XMLHttpRequest()
if (xhr.upload) {
    xhr.upload.onprogress = function progress(e) {
        if (e.total > 0) {
            e.percent = e.loaded / e.total * 100
        }
    }
}

3. Объект XMLHttpRequest получает API, связанный с ответом.

После получения ответа первым делом необходимо проверитьstatusАтрибуты. чтобы определить, что ответ успешно возвращен. БудуHTTPКод состояния200в знак успеха. Код состояния304Указывает, что запрошенный ресурс не был изменен, версия, кэшированная в браузере, может быть использована напрямую, и она также считается действительной.

Связанный заголовок ответа

  • Content-Type: сервер сообщает клиенту тип и кодировку символов содержимого ответа. Например:Content-Type: text/html; charset=utf-8.
  • Content-Length: сервер сообщает клиенту размер объекта ответа. Например:Content-Length: 8368.
  • Content-Encoding: сервер сообщает клиенту возвращенный формат кодирования сжатия. Например:Content-Encoding: gzip, deflate, br.

Больше ссылок:developer.Mozilla.org/this-cn/docs/…

статусное свойство

statusСвойство возвращает целое число, представляющее ответ от сервера.HTTPкод состояния. Если сервер не возвращает код состояния, то это свойство по умолчанию равно200.请求发出之前,该属性为0. Это свойство доступно только для чтения.

if (xhr.readyState === 4) {
  if (xhr.status >= 200 && xhr.status < 300) {
    // 处理服务器的返回数据
  }
}

свойство statusText

statusTextСвойство возвращает строку, представляющую описание состояния, отправленное сервером. НапримерOKа такжеNot Found. Перед отправкой запроса значением этого свойства является пустая строка. Если сервер не возвращает подсказку о состоянии, значение этого свойства по умолчанию равноOK. Это свойство доступно только для чтения.

пройти проверкуstatusсвойства для определения следующего действия, не полагайтесь наstatusText,потому чтоstatusTextМенее надежен при использовании в разных браузерах.

свойство ответа

responseСвойства представляют данные, возвращаемые сервером. Это может быть любой тип данных, такой как строка, объект, двоичный объект и т. д. Конкретный тип определяетсяXMLHttpRequest.responseTypeатрибутивное решение. Это свойство доступно только для чтения.

Если запрос не удался или данные неполные, это свойство равноnull.

const xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
  if (xhr.readyState === 4) {
    console.log(xhr.response)
  }
}

Свойство responseText

responseTextСвойство возвращает строку, полученную от сервера, это свойство доступно только для чтения.

if (xhr.readyState === 4) {
  if (xhr.status >= 200 && xhr.status < 300) {
    // 处理服务器的返回数据
    console.log(xhr.responseText)
  }
}

свойство responseXML

Если тип содержимого ответа"text/xml"или"application/xml", это свойство будет содержать данные ответа, содержащиеHTMLилиXMLобъект документа. Это свойство доступно только для чтения.

Независимо от типа содержимого содержимое тела ответа сохраняется в свойстве responseText. Для данных, отличных от XML, значение атрибута responseXML будет нулевым.

свойство responseURL

responseURLСвойство представляет собой строку, представляющую URL-адрес сервера, отправляющего данные. еслиURLEmpty возвращает пустую строку. еслиURLимеет якорную точку, он расположен вURL#Следующий контент будет удален. Если на стороне сервера происходит переход, это свойство возвращает последний URL-адрес, фактически вернувший данные.

const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://example.com/test', true)
xhr.onload = function () {
  // 返回 http://example.com/test
  console.log(xhr.responseURL)
}
xhr.send(null)

Метод getResponseHeader()

getResponseHeader()метод возвращаетHTTPЗначение указанного поля в информации заголовка, если ответ от сервера не получен или указанное поле не существует, вернутьnull. Аргументы этого метода не чувствительны к регистру.

const xhr = new XMLHttpRequest()
xhr.onload = function onload() {
   console.log(xhr.getResponseHeader('Content-Type'))
}
xhr.open('post', '/server', true)
xhr.send(null)

Если есть несколько полей с одинаковым именем, их значения будут объединены в строку, где каждое поле будет разделяться запятой+пробелом.

Метод getAllResponseHeaders()

getAllResponseHeaders()Метод возвращает строку, представляющую всеHTTPинформация заголовка. Формат представляет собой строку, используемую между каждой информацией заголовка.CRLFРазделение (возврат каретки + перевод строки), если ответ от сервера не получен, это свойствоnull. Если возникает сетевая ошибка, это свойство представляет собой пустую строку.

const xhr = new XMLHttpRequest()
xhr.onload = function onload() {
 const responseHeaders = 'getAllResponseHeaders' in xhr ? xhr.getResponseHeaders() : null
}
xhr.open('post', '/server', true)
xhr.send(null)

Приведенный выше код используется для получения всей информации заголовка, возвращаемой сервером. Возвращаемое значение может быть строкой, подобной следующей.

content-encoding: gzip\r\n
content-length: 2020\r\n
content-type: text/html; charset=utf-8\r\n

Эту строку необходимо манипулировать, чтобы использовать ее правильно.

const str = 'date: Fri, 08 Dec 2017 21:04:30 GMT\r\n'
  + 'content-encoding: gzip\r\n'

function trim(str) {
  return str.replace(/^\s*/, '').replace(/\s*$/, '')
}
function parseHeaders(headers) {
  if (!headers) {
    return {}
  }
  const parsed = {}
  let key, val, i
  const arr = headers.split(/[\r\n]+/)
  arr.forEach((line) => {
    i = line.indexOf(':')
    key = trim(line.substr(0, i)).toLowerCase()
    val = trim(line.substr(i + 1))
    if (key) {
      parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val
    }
  })
  return parsed
}
//{date: "Fri, 08 Dec 2017 21:04:30 GMT", content-encoding: "gzip"}
console.log(parseHeaders(str))

Справочная статья

book.Douban.com/subject/105…

nuggets.capable/post/684490…

сегмент fault.com/ah/119000000…

Уууу. HTML5rocks.com/this/tutorial…

IM District.com/post/deny-i…

Ууху. Call.com/question/28…

javascript.ruanyifeng.com/film/ajax.contract…