JavaScript/jQuery: как убедиться, что событие междоменного отслеживания кликов успешно выполнено до того, как пользователь покинет страницу?

Я реализую отслеживание кликов с различных страниц в нашей корпоративной интрасети, чтобы добавить некоторые крайне необходимые функции популярных ссылок из краудсорсинга («самые популярные ссылки в вашем отделе за последние 24 часа» и т. д.)

Я использую jQuery .live() для привязки к событию mousedown для всех элементов ссылки на странице, фильтрую событие, а затем запускаю псевдо-ajax-запрос с различными данными на внутренний сервер перед возвратом true, чтобы действие ссылки срабатывает:

$("#contentarea a").live("mousedown", function(ev) {
    //
    // detect event, find closest link, process it  here
    //
    $.ajax({
        url: 'my-url',
        cache: false,
        dataType: 'jsonp',
        jsonp: 'cb',
        data: myDataString,
        success: function() {
            // silence is golden -- server does send success JSONP but 
            // regardless of success or failure, we allow the user to continue
        }
    });

    return true; // allow event to continue, user leaves the page.
}

Как вы, наверное, догадались из вышеизложенного, у меня есть несколько ограничений:

  • Внутренний сервер отслеживания находится в другом субдомене, чем вызывающая страница. Я не могу обойти это. Вот почему я использую JSONP (и GET), а не правильный AJAX с POST. Я не могу реализовать прокси-сервер AJAX, поскольку веб-серверы не имеют исходящего сетевого доступа для сценариев.
  • Это, вероятно, не имеет значения, но в интересах полного раскрытия содержимое и сценарий находятся внутри iframe «основного содержимого» (и это не изменится. Я, вероятно, в конечном итоге перемещу прослушиватель событий в родительский фрейм, чтобы отслеживать его ссылки и весь дочерний контент, но шаг 1 — заставить его работать правильно в упрощенном случае «1 дочернее окно»). Родительский и дочерний домены являются одним доменом.
  • Серверная часть — это IIS/ASP (опять же, ограничение — не спрашивайте!), поэтому я не могу немедленно разветвить внутренний процесс или иным образом завершить ответ, но продолжать обработку, как я мог бы на лучшей платформе.

Несмотря на все это, по большей части система работает — я кликаю по ссылкам на странице, и они почти незаметно появляются в базе данных.

Однако это ненадежно — для большого количества ссылок, особенно внешних ссылок, для которых задана цель «_top», они не отображаются. Если ссылка открывается в новой вкладке или окне, она регистрируется ОК.

Я исключил ошибки скрипта - кажется, что либо:

(a) запрос никогда не доходит до серверной части вовремя; или

(b) запрос выполняется, но ASP обнаруживает, что вскоре после этого клиент отключается, и, поскольку это запрос GET, не обрабатывает его.

Подозреваю (б), т.к. латентность к серверу очень быстрая и многие ссылки регистрируются ОК. Если я помещаю всплывающее окно с предупреждением после того, как событие срабатывает, или устанавливаю возвращаемое значение как false, щелчок регистрируется ОК.

Любые советы о том, как я могу решить эту проблему (в контексте, что я не могу изменить свои ограничения)? Я не могу сделать запрос GET синхронным, так как это не настоящий AJAX.

Вопрос. Было бы лучше, если бы я отправлял запрос POST в ASP? Если (b) является виновником, будет ли он вести себя по-разному для POST и GET? Если это так, я мог бы использовать скрытый iframe/форму для POST данных. однако я подозреваю, что это будет медленнее и неуклюже, и все еще может не успеть. Я бы не смог прослушать, чтобы увидеть, завершается ли запрос, потому что он междоменный.

Вопрос. Можно ли просто добавить в скрипт задержку после запуска запроса GET? Как мне сделать это в однопоточном режиме? Мне нужно вернуть true из моей функции, чтобы в конечном итоге сработало событие по умолчанию, поэтому я не могу использовать setTimeout(). Будет ли срабатывать замкнутый цикл, ожидающий «успеха», и устанавливать некоторую переменную работу? Я беспокоюсь, что это слишком заморозит вещи, и ответ будет замедлен. Я предполагаю, что плагин jQuery delay() тоже просто цикл?

Или что-то еще, о чем я не думал, может быть виновником?

Мне не нужна пуленепробиваемая надежность. Если все ссылки одинаково уловимы в 95% случаев, это нормально. Однако прямо сейчас некоторые ссылки улавливаются в 100% случаев, в то время как другие не улавливаются, что не соответствует тому, чего я хочу достичь.

Заранее спасибо.


person Jhong    schedule 17.07.2010    source источник


Ответы (3)


Я бы попытался вернуть false из обработчика события ссылки, запомнить URL-адрес и уйти только после успешного выполнения запроса JSONP. Надеюсь, это не должно добавить слишком много задержки. Учитывая, что вы находитесь в интранете, это может быть нормально.

person Igor Zevaka    schedule 17.07.2010
comment
Спасибо - я думал об этом. Проблема в том, что к некоторым ссылкам уже привязаны события javascript (например, показать в толстом ящике). Есть ли способ сохранить все событие, а затем выполнить его позже? Обратите внимание, что это не события onclick, они также динамически применяются с использованием jQuery. - person Jhong; 17.07.2010

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

$(window).unload(function(event) {
  // tracking code here
});
person kingjeffrey    schedule 17.07.2010
comment
Спасибо - хорошая мысль. Но учитывая, что мне все еще нужно вернуть true и я не могу отправить запрос синхронно, не будет ли это по-прежнему подлежать отключению? Также некоторые ссылки открываются в новых окнах или во всплывающем окне. Я предполагаю, что они не будут запускать window.onunload, и мне тоже нужно их отслеживать. - person Jhong; 17.07.2010
comment
Да, unload может быть не для вас событием. Не имея возможности отправить его синхронно, единственный вариант, который я могу придумать, - это своего рода цикл задержки для искусственного замедления вашего кода. Но это меньше, чем желательно. - person kingjeffrey; 17.07.2010
comment
Я думаю, что мне придется попробовать это. Просто немного боюсь заблокировать системы людей. Многие пользователи до сих пор используют IE6 на довольно старых ноутбуках. Если я зацикливаюсь, ожидая завершения запроса или истечения времени ожидания, будут ли выполняться фоновые потоки? У меня есть несколько анимаций на странице и т. д. Было бы неплохо, если бы они продолжались в течение полсекунды или около того, что требуется для моего цикла. - person Jhong; 17.07.2010
comment
Другие процессы должны продолжать работать, но в более ранних версиях браузеров вы можете увидеть их блокировку. Если это не настоящий ajax, как вы узнаете, когда запрос будет выполнен? Вы просто выполняете базовый цикл, пока не сработает setTimeout, и надеетесь? Это жесткий набор ограничений, с которыми вы работаете! - person kingjeffrey; 17.07.2010
comment
JSONP с GET может получить ответ. Вот почему я сдержанно использую POST/iframe, потому что ответ будет помещен в песочницу. тем не менее, я не реагирую на ответ - просто позволяю пользователю перейти к тому, что он щелкнул. - person Jhong; 17.07.2010
comment
Я думаю, что комбинация вашего исходного ответа и цикла будет работать. Поскольку сбоем являются только события, запускающие window.unload, я также могу подключиться к onunload и добавить туда только задержку. Я, вероятно, могу слушать максимум, скажем, 1 секунду, прежде чем сдаться и двигаться дальше. Я также думаю, что создание искусственного цикла вокруг кода ASP может помешать ему отказаться от выполнения. Я дам вам знать результат. Вероятно, все вышеперечисленное. - person Jhong; 17.07.2010
comment
Если вы получите ответ, почему вы не можете установить async: false и избежать взлома цикла? - person kingjeffrey; 17.07.2010

Решено!

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

Затем я попробовал тугие петли, и они тоже не были надежными.

Наконец, я просто сдался и использовал динамически созданную форму, которая отправляла результаты POST, с целью, установленной на скрытый iFrame.

Это работает надежно — кажется, что браузер делает паузу, чтобы завершить свой POST-запрос, прежде чем двигаться дальше, и ASP учитывает POST. Оказывается, это совсем не "хлипко". Конечно, из-за модели безопасности браузера я не вижу результата... но в данном случае это не имеет значения.

Теперь корю себя за то, что сначала не попробовал этот вариант.

person Jhong    schedule 19.07.2010