AJAX запускает и забывает, ищет противоположность отправляемому на сервер событию

Являются ли эти API-интерфейсы симметричными для события, отправленного сервером, для генерирования событий запуска и забывания от браузера к серверу? Я знаю, как не отвечать на запрос на стороне сервера, но как сказать браузеру, что ему не нужно ждать ответа?

Цель здесь - сэкономить ресурсы на стороне клиента, скажем, вы хотите посылать на сервер 10k событий как можно быстрее, не заботясь о том, что сервер отвечает.

Редактировать: Хотя это в основном не имеет отношения к вопросу, вот некоторая предыстория о проекте, над которым я работаю, который будет использовать "AJAX Fire-and-Forgot". Я хочу создать сетевую библиотеку JavaScript для Scala.js, в качестве одного из приложений которой будет использоваться транспортный уровень между актерами Akka на JVM и в браузере (скомпилировано с Scala.js). Когда WebSockets недоступны, я хочу иметь некоторый запасной вариант, и наличие ожидающего соединения на время двусторонней передачи для каждого сообщения JS->JVM недопустимо.

6 ответов

Как вы спросили "как сказать браузеру, что ему не нужно ждать ответа?" Я предполагаю, что вы не хотите обрабатывать ответ сервера.

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

Подробнее здесь

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

var image = new Image();
image.src = "your-script.php?id=123&other_params=also";

PRO: легко реализовать меньшую нагрузку на сервер / клиент, чем запрос ajax

Минусы: вы можете отправлять только запросы GET, используя этот appproach.

редактировать

Для большего количества ссылок:

http://help.yahoo.com/l/us/yahoo/ywa/faqs/tracking/advtrack/3520294.html

https://support.google.com/dfp_premium/answer/1347585?hl=en

Как создать и внедрить код отслеживания пикселей

Снова они используют ту же технику пиксельного изображения.

Итак, для ясности, вы пытаетесь использовать XMLHttpRequest в качестве прокси для вашего сетевого взаимодействия, что означает, что вы на 100% зависите от того, что XMLHttpRequest предлагает вам, верно?

Я полагаю, что если вы собираетесь придерживаться XMLHttpRequest для этого, вам просто придется смириться с получением ответа от сервера. Просто сделайте вызов асинхронно и обработайте ответ неактивной функцией. Подумайте, что предложил кто-то другой, используя очередь на сервере (или асинхронный метод на сервере), чтобы вы немедленно вернулись к клиенту. В противном случае, я действительно считаю, что JavaScript - это не тот инструмент, который вы описываете.

XMLHttpRequest будет отличаться реализацией (представляя более или менее общий интерфейсный контракт) в каждом браузере. Я имею в виду, что Microsoft изобрела эту вещь, затем другие производители браузеров подражали ей, а затем вуаля, все стали называть это Web 2.0. Дело в том, что если вы слишком сильно нажмете на рыхлый центр XMLHttpRequest, вы можете по-разному вести себя в разных браузерах.

Насколько мне известно, XMLHttpRequest строго использует TCP (без опции UDP), поэтому по крайней мере ваш клиент будет получать TCP ACK с сервера. Невозможно сказать серверу, чтобы он не отвечал на этом уровне. Он запекается в сетевой стек TCP/IP.

Кроме того, для связи используется протокол HTTP, поэтому сервер ответит заголовками HTTP... верно? Я имею в виду, это просто способ определения протокола. Говорить, что HTTP - это что-то другое, - это все равно, что говорить кошке лаять, как курица.

Даже если вы можете отменить запрос на стороне клиента, вызвав abort() для XMLHttpRequest, вы не отмените его на стороне сервера. Для этого, даже если бы это было возможно с XMLHttpRequest, потребовался бы дополнительный запрос, отправленный полностью на сервер, чтобы сказать ему отменить ответ на предыдущий запрос. Как узнать, какой ответ отменить? Вы должны были бы управлять идентификаторами запроса некоторого вида. Вы должны быть устойчивы к отмене запросов отмены заказа. Сложно.

Итак, вот мысль (я просто обдумываю вслух): XMLHttpRequest от Microsoft был основан, по крайней мере, в духе, на более ранней технологии Microsoft времен Visual Interdev, которая использовала Java-апплет на клиенте для асинхронного запуска запроса к сервер, затем он передаст управление вашей предпочтительной функции обратного вызова JavaScript, когда ответ появится, и т.д. Довольно знакомо.

То, что запрос асинхронного запроса Java был искажен в течение всего фиаско судебного процесса против Sun и Microsoft. Я слышал слухи о том, что некий оригинальный генеральный директор Майкрософт может взорваться, когда узнает о технологиях Microsoft, внедряемых с использованием Java, и убить технику. Кто знает? Я был недоволен, когда эта возможность исчезла на пару лет, а потом снова обрадовался, когда в итоге появился XMLHttpRequest.

Может быть, вы видите, куда я иду, здесь...:-)

Я думаю, что, возможно, вы пытаетесь выжать поведение из XMLHttpRequest, для которого оно просто не создано.

Ответ может состоять в том, чтобы просто написать свой собственный Java-апплет, выполнить некоторое программирование сокетов и сделать так, чтобы он делал то, что вы хотите видеть из него. Но тогда, конечно, у вас будут проблемы с людьми, у которых в браузерах не включена Java, что усугубляется всеми недавними проблемами безопасности Java. Итак, вы смотрите на сертификаты для подписи кода и так далее. И вы также смотрите на проблемы, которые вам нужно решить на стороне сервера. Если вы по-прежнему используете HTTP и работаете через свой веб-сервер, веб-сервер все равно будет хотеть отправлять HTTP-ответы, что по-прежнему будет связывать ресурсы на сервере. Вы можете сделать эти действия на сервере асинхронными, чтобы сокеты TCP не оставались связанными дольше, чем необходимо, но вы все еще связываете ресурсы на стороне сервера.

Мне удалось получить ожидаемое поведение, используя очень маленький тайм-аут 2 мс. Следующий вызов виден серверу, но соединение закрывается на стороне клиента перед любым ответом от сервера:

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
  if (xhr.readyState == 2) {
    alert("Response header recived, it was not a fire-and-forget...");
  }
};
xhr.open("POST", "http://www.service.org/myService.svc/Method", true);
xhr.timeout = 2;
xhr.send(null);

Это не совсем удовлетворительно, потому что время ожидания может меняться между браузером / компьютером (например, 1 мс не работает на моей установке). Использование большого тайм-аута порядка 50 мс означает, что клиент может достичь максимума одновременных открытых соединений (6 в моей настройке).

Похоже, вы пытаетесь решить не ту проблему. Вместо того, чтобы иметь дело с этим на клиенте, почему бы не обработать это на стороне сервера.

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

У вас не будет такого же тонкого контроля над соединением с XHR, как с WebSockets. В конечном счете, именно браузер управляет жизненным циклом HTTP-соединения.

Вместо того, чтобы переходить от WebSockets к дискретным соединениям XHR, возможно, вы можете хранить и группировать свои события. Например:

Клиент JS

function sendMessage(message) {
    WebSocketsAvailable ? sendWithWebSockets(message) : sendWithXHR(message);
}

var xhrQueue = [];

function sendWithXHR(message) {
    xhrQueue.push({
        timestamp: Date.now(),  // if this matters
        message: message
    });
}

function flushXhrQueue() {
    if (xhrQueue.length) {
        var req = new XMLHttpRequest();
        req.open('POST', 'http://...');
        req.onload = function() { setTimeout(flushXhrQueue, 5000); };
        // todo: needs to handle errors, too
        req.send(JSON.stringify(xhrQueue));
        xhrQueue = [];
    }
    else {
        setTimeout(flushXhrQueue, 5000);
    }
}

setTimeout(flushXhrQueue, 5000);

На сервере, возможно, вы можете иметь две конечные точки: одну для WebSockets и одну для XHR. Обработчик XHR десериализует объект очереди JSON и вызывает (один раз для каждого сообщения) тот же обработчик, который используется обработчиком WebSockets.

Псевдокод сервера

function WSHandler(message) {
    handleMessage(message, Date.now());
}

function XHRHandler(jsonString) {
    var messages = JSON.parse(jsonString);

    for (var messageObj in messages) {
        handleMessage(messageObj.message, messageObj.timestamp);
    }
}

function handleMessage(message, timestamp) {
    ...
}

Использование XMLHttpRequest для отправки асинхронного запроса (т. Е. Когда вас не волнует, успешен ли он или каков ответ:

var req = new XMLHttpRequest();
req.open('GET', 'http://my.url.goes.here.com');
req.send();

Кстати, вы можете сделать то же самое с объектом Image, кстати:

new Image().src = 'http://my.url.goes.here.com';

Подход к изображениям работает особенно хорошо, если вы делаете междоменные запросы, поскольку изображения не подпадают под ограничения безопасности того же источника, что и запросы XHR. (Кстати, это хорошая практика, но не обязательно, чтобы ваша конечная точка возвращала ответ PNG или GIF размером 1x1 пиксель с соответствующим Content-Type, чтобы избежать предупреждений консоли браузера, таких как "Ресурс интерпретируется как изображение, но передается с типом MIME text/html".)

Другие вопросы по тегам