Возможна коллизия двух запросов ajax? - PullRequest
7 голосов
/ 07 июня 2011

У меня проблемы с одним из моих сайтов, на котором при загрузке страницы выполняются два ajax-запроса. Я использую jQuery в сочетании с PHP-приложением на основе Zend Framework.

Соответствующий HTML (упрощенный) выглядит так:

<select id="first">
     <option value="1">First Option</option>
     <option value="2">Second Option</option>
</select>
<div class="first_block"></div>

<select id="second">
     <option value="1">First Option</option>
     <option value="2">Second Option</option>
</select>
<div class="second_block"></div>

Вот как выглядит мой jQuery:

$(document).ready(function(){

// function to update the first block
var updateFirstBlock = function(){
    var param = $(this).val();
    $.ajax('module/controller/action/param/' + param, {
        'success': function(data){
            $('.first_block').html(data);
        }
    });
};

// bind and trigger the first update function
$('select#first').bind('change', updateFirstBlock );
$('select#first').trigger('change');


// function to update the second block
var updateSecondBlock = function(){
    var param= $(this).val();
    $.ajax('module/controller/another-action/param/' + param, {
        'success': function(data){
            $('.second_block').html(data);
        }
    });
};

// bind and trigger the second update function
$('select#second').bind('change', updateSecondBlock );
$('select#second').trigger('change');

});

Приложение PHP просто возвращает некоторый контент в зависимости от того, какое значение распределено.

Что происходит при загрузке страниц, так это то, что в девяти из десяти случаев один из двух запросов не получает ответа. Другой получает 200 OK, а один из них терпит неудачу. Там нет регулярности, который запрос не удается.

Возможно ли, что в конфигурации веб-серверов (Apache 2.2) что-то не так, и два одновременно запущенных запроса ограничивают друг друга?

EDIT

Если я установлю оба запроса на async: false, они всегда будут выполняться правильно. Так что я думаю, что должно быть столкновение.

РЕДАКТИРОВАТЬ 2

Возможной причиной такого поведения может быть блокировка сеанса php. Я рассмотрю это дальше.

1 Ответ

1 голос
/ 07 июня 2011

Кажется, вы определенно находитесь на правильной стойке с блокировкой сеанса PHP:

Примечания о блокировке сеанса (параллелизм)

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

Некоторые люди обходят это, вызывая session_write_close(), как только они закончили записывать любые данные в $_SESSION - они могут продолжать читать данные даже после того, как они их вызвали. Недостаток session_write_close() заключается в том, что ваш код все еще будет блокироваться при первом вызове session_start() на любой странице сеанса, и что вам придется посыпать session_write_close() везде, где вы используете сеансы, как толькокак вы можете.Это все еще очень хороший метод, но если ваш доступ к сеансу следует определенным шаблонам, у вас может быть другой способ, который требует меньше изменений вашего кода.

Идея состоит в том, что если ваш код сеанса в основном читает сессий и редко пишет в них, тогда вы можете разрешить параллельный доступ.Чтобы предотвратить полностью испорченные данные сеанса, мы заблокируем хранилище резервных копий сеанса (обычно это файлы tmp) во время записи в них.Это означает, что сеанс заблокирован только на короткое время, которое мы записываем в резервное хранилище.Однако это означает, что если две страницы загружаются одновременно и обе изменяют сеанс, Last One Wins .В зависимости от того, кто загружает первым, его данные перезаписываются данными, загружаемыми вторыми.Если с вами все в порядке, вы можете продолжить, в противном случае используйте метод session_write_close, описанный выше.

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

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

Скопируйте пример из session_set_save_handler () в ваш включаемый файл выше, где вы начинаете свои сеансы.Измените метод write () для сеанса:

function write($id, $sess_data)
{
  global $sess_save_path, $sess_session_name;

  $sess_file = "$sess_save_path/sess_$id";
  if ($fp = @fopen($sess_file, "w")) {
   flock($fp,LOCK_EX);
   $results=fwrite($fp, $sess_data);
   flock($fp,LOCK_UN);
   return($results);
  } else {
   return(false);
  }

}

Возможно, вы также захотите добавить метод GC (Сборка мусора) для сеансов.

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

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

Ref: http://ch2.php.net/manual/en/ref.session.php#64525


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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...