Почему нельзя использовать как ajax, так и событие, отправленное сервером?

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

"сервер отправил событие": отправляет текст на консоль в произвольное время

если я использую только ajax, я получаю данные с сервера. Но если я использую оба подхода, я не получал данные от сервера в ответ на запрос ajax, но все равно получал сообщение в ответ на "событие, отправленное сервером". Я даже не получил сообщение об ошибке из запроса ajax. Может кто-нибудь объяснить это?

клиент

var evtSource = new EventSource("config/addRemoveEvent.php");
evtSource.onmessage = function(e) {
  //var newElement = document.createElement("li");
  console.log("listening: "+ e.data);
  //newElement.innerHTML = "message: " + e.data;
  //eventList.appendChild(newElement);
}   

var data = {
    'action':'Initiate brief calendar', 
    'selectedMonth': month, 
    'selectedYear': year
};

var $request = $.ajax({
    type: "GET",
    dataType: "text",
    url: "config/addRemoveEvent.php",
    data: data,
    beforeSend: function(){
        console.log('start sending request');

    }
});

$request.fail(function(){
    console.log('fail');
}); 
$request.done(function(data){
    // change bg color of the cells that contain events;
    console.log(data);
});

сервер

header("Content-Type: text/event-stream\n\n");
date_default_timezone_set("America/New_York");

while (1) {

  if (!$counter) {
    echo 'data: This is a message at time ' . $curDate . "\n\n";
    $counter = rand(1, 3);
  }

  ob_flush();
  flush();
  sleep($counter);
}

// return the date has event in a given month 
if($_GET['action'] == "Initiate brief calendar"){
    echo 'hello';
}

1 ответ

Решение

Ваш php скрипт правильный для SSE:

  • отправляет Content-Type: text/event-stream
  • это бесконечный цикл, чтобы продолжать посылать данные клиенту

С другой стороны, когда вы используете $.ajax он ожидает серверный скрипт, который отправит ему кучу данных и закроет соединение.

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

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

date_default_timezone_set("America/New_York");

// return the date has event in a given month 
if($_GET['action'] == "Initiate brief calendar"){
    echo 'hello';
    exit;
}

//session_write_close();  //See below

header("Content-Type: text/event-stream\n\n");
while (1) {

  if (!$counter) {
    echo 'data: This is a message at time ' . $curDate . "\n\n";
    $counter = rand(1, 3);
  }

  ob_flush();
  flush();
  sleep($counter);
}

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

Поэтому, если вы используете сеансы, но также планируете выполнять вызовы ajax одновременно с выполнением сценария SSE, отключите сценарий SSE от сеанса. Я показал, прокомментировал, выше, где вы могли бы положить session_write_close() для достижения этой цели.

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