Показать сообщение отдельно
  #33 (permalink)  
Старый 11.12.2021, 18:19
Профессор
Отправить личное сообщение для Rise Посмотреть профиль Найти все сообщения от Rise
 
Регистрация: 07.11.2013
Сообщений: 458

developer_, сначала вам надо понять как устроен XMLHttpRequest и fetch.

Есть загрузка на сервер (upload) и есть загрузка на клиент (download). Другими словами, есть http-запрос (request) и есть http-ответ (response).

Так вот, событие readystatechange это только загрузка на клиент. Так исторически сложилось, изначально не было событий прогресса: loadstart, progress, load, error, abort, timeout, loadend. Сейчас readystatechange - устаревшее:
xhr.onreadystatechange = function() {
    if (this.readyState == 4) {
        if (this.status == 200) {
            // ok
        } else {
            // server error
        }
    }
};

Далее, что касается ошибок. Есть ошибки ответа сервера (http status codes) и есть ошибки сети (network errors). Имя ошибки сети нельзя получить через скрипт. Почему нельзя и какие я писал здесь, повторяться не буду. Событие abort это результат вызова xhr.abort() и отношения к делу не имеет.

Так вот, событие error это только ошибки сети, а ошибки сервера проверяются в другом месте:
var xhr = new XMLHttpRequest;
xhr.open('POST', '/');
xhr.onload = function() {
    if (this.status == 200) {
        // ok
    } else {
        // server error
    }
};
xhr.onerror = function() {
    // network error
};
xhr.send(new FormData);

Тоже самое и в fetch:
fetch('/', {
        method: 'POST',
        body: new FormData,
    })
    .then(response => {
        if (response.ok) {
            // 200-299 status
        } else {
            // server error
        }
    })
    .catch(error => {
        // network error
    });

Далее, нужно понимать последовательность выполнения событий. События load, error, abort, timeout - взаимоисключающие. Остальные имеют определенный порядок:
var xhr = new XMLHttpRequest;

xhr.open('POST', '/');

xhr.onloadstart = log; // 1

xhr.upload.onloadstart = log; // 2
xhr.upload.onprogress = log;  // 3
xhr.upload.onload = log;      // 4
xhr.upload.onerror = log;     // 4
xhr.upload.onabort = log;     // 4
xhr.upload.ontimeout = log;   // 4
xhr.upload.onloadend = log;   // 5

// download
xhr.onprogress = log; // 6
xhr.onload = log;     // 7
xhr.onerror = log;    // 7
xhr.onabort = log;    // 7
xhr.ontimeout = log;  // 7
xhr.onloadend = log;  // 8

xhr.onreadystatechange = log; // 6-8

xhr.send(new FormData);

function log(e) {
    console.log(String(this), e.type, e.loaded, xhr.readyState, xhr.status);
}

В fetch - вообще нет событий прогресса, поэтому ничего понимать не надо.


Вывод, то что вы делаете с сокетами на уровне TCP генерирует ошибку сети, а скрипт ее не видит, во 1-х, потому что он работает на другом уровне - HTTP, во 2-х, потому что чтение таких ошибок запрещено по причине безопасности.


То что касается последних ваших экспериментов можно сказать следующее:

1. Если Apache продолжает обслуживать запрос клиента после отправки ответа об ошибке, вопреки своей же документации, где написано "If the client request exceeds that limit, the server will return an error response instead of servicing the request.", то это баг.

2. Если клиент, Браузер, продолжает отправлять тело сообщения после получения ответа об ошибке, вопреки своей же спецификации, где написано "If the client sees a response that indicates the server does not wish to receive the message body and is closing the connection, the client SHOULD immediately cease transmitting the body and close its side of the connection.", то это тоже баг.

Последний раз редактировалось Rise, 11.12.2021 в 18:27.
Ответить с цитированием