Обновить всю страницу по запросу Ajax

У меня есть запрос AJAX, который может иметь два возможных результата:

  1. Сервер отвечает сообщением, которое я должен разместить в <div>
  2. Сервер отвечает HTML-страницей, в этом случае мне нужно заменить текущую страницу на новую и изменить адрес (клиент знает адрес перед запросом).

Каким будет решение, если у меня есть запрос AJAX, который должен обрабатывать оба этих случая?

  url = "http://example.com" ajax.request(callback) function callback(response) { if (case2(response)) { history.pushState({}, "New page", url); document.innerHTML = response } else { updateDiv(response) } } 

Я заинтересован в правильном способе реализации первой ветви, или если сервер может каким-то образом составить заголовки, которые заставят браузер обрабатывать ответ как обычный ответ HTTP и обновлять местоположение и содержимое страницы, что-то вроде перенаправления с данным контентом ,

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

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

В случае, если вы вынуждены пойти по пути, который вы уже прошли, и при условии, что контент ответа не очень велик, вы можете попробовать Javascript-URI. В принципе, URI в виде javascript:"string" будет загружать новую страницу, для которой эта строка является исходным кодом. Итак, если response уже является строкой, просто назначить javascript:response to window.location.href должно быть достаточно. Может быть, вам нужно немного ускользнуть. И я не знаю, как кросс-браузер-совместимый этот подход.

 <a href="javascript:response">load</a> 

также возможно.

Вариантом этого является создание URL-адреса не с именем переменной, а с фактическими строковыми данными. подобно

 function source2url(src) { // make valid javascript string from source text var esc1 = src .replace(/\\/g, '\\\\') .replace(/\'/g, '\\\'') .replace(/\x0A/g, '\\x0A') .replace(/\x0D/g, '\\x0D'); // make valid url from that return "javascript:'" + encodeURIComponent(esc1) + "'"; } window.location.href = source2url(response); 

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

ОБНОВИТЬ

Аналогичный подход заключается в использовании кодирования base64 в URI данных. В записи в Википедии объясняется, как это работает, включая пример javascript. Тем не менее, вам нужно будет как -то закодировать содержимое base64 . (Примечание. Вы можете использовать URI данных с кодировкой base64 или без нее. Вы должны увидеть, что дает вам более короткие URI для вашего конкретного контента.)

Однажды у меня была аналогичная проблема. Была возвращена полная страница ошибки вместо простого фрагмента HTML. В конце концов мы установили это, изменив логику, но вот одно из решений, которые я нашел:

 document.open(); document.write(responseText); document.close(); 

Причина, по которой мы отказались от этого, заключается в том, что на IE возникли некоторые проблемы. Я не терял времени, чтобы исследовать причину, но при попытке написать строку он выбрал исключение «Доступ запрещен». Я думаю, что есть теги <meta> которые путают IE, или, может быть, условные комментарии, я не уверен. (Он работал, когда я использовал несколько простых страниц …)

Итог: вам не нужно это делать, но если вы ничего не можете сделать (например, вернуть строку url), код может работать.

Это очень просто, если ответ действительно является XML.

 var new_doc = (new DOMParser).parseFromString(response, "application/xml"); document.replaceChild(document.adoptNode(new_doc.doctype), document.doctype); document.replaceChild(document.adoptNode(new_doc.documentElement), document.documentElement); 

Поскольку запрос содержит обновленный ответ, вот мое решение, использующее API истории HTML5 с jQuery . Он должен работать легко, объединяя части PHP и HTML в один файл.

Мое решение позволяет AJAX возвращать следующее:

  1. Сообщение через AJAX, которое обновляет контейнер <div> .
  2. URL-адрес, который заставляет браузер перенаправлять URL-адрес
  3. Полная HTML-страница, которая вызывает историю истории history.pushState() чтобы добавить текущий URL-адрес в историю браузера и заменяет весь HTML на странице HTML-кодом, возвращенным из AJAX.

PHP

Это всего лишь образец того, что PHP-скрипт должен будет вернуть, когда он вызывается через AJAX. Он показывает, как кодировать флаги, чтобы определить, должен ли вызов AJAX обновлять контейнер или загружать новую страницу и как возвращать его результат через JSON через json_encode . Для полноты я назвал этот скрипт test.php .

 <?php // Random messages to return $messages = array( 'Stack Overflow', 'Error Message', 'Testing' ); // If the page was requested via AJAX if( isset( $_POST['ajax'])) { $response = array( 'redirect' => // Flag to redirect ( rand() % 2 == 0) ? true : false, 'load_html' => // Flag to load HTML or do URL redirect ( rand() % 2 == 0) ? true : false, 'html' => // Returned HTML '<html><head><title>AJAX Loaded Title</title></head><body>It works!</body></html>', 'title' => 'History API previous title', 'message' => // Random message $messages[ (rand() % count( $messages)) ] ); echo json_encode( $response); exit; } 

JS

Поскольку я использую jQuery, давайте начнем с этого. Следующее отправляет AJAX POST на сервер, на указанный выше PHP-скрипт по адресу URL test.php . Обратите внимание, что он также устанавливает параметр POST ajax как true , позволяя скрипту PHP обнаруживать, что он получил запрос AJAX. Поле dataType сообщает jQuery, что ответ сервера будет в JSON и что он должен декодировать этот JSON для объекта JSON в dataType ответа. Наконец, обратный вызов success , который запускается при успешном получении ответа AJAX, определяет, что делать на основе флагов, отправленных с сервера.

 $.ajax({ type: 'POST', url: "/test.php", data: {ajax : true}, dataType: "json", success: function( json) { if( json.redirect) { if( json.load_html) { // If the History API is available if( !(typeof history.pushState === 'undefined')) { history.pushState( { url: redirect_url, title: document.title}, document.title, // Can also use json.title to set previous page title on server redirect_url ); } // Output the HTML document.open(); document.write( json.html); document.close(); } else { window.location = redirect_url; } } else { $('#message').html( json.message); } }, }); 

HTML

Вот полный источник HTML моего тестируемого файла. Я тестировал его в FF4 – FF8. Обратите внимание, что jQuery предоставляет ready метод для предотвращения выполнения JS до загрузки DOM. Я также использовал хостинг Google jQuery, поэтому вам не нужно загружать копию jQuery на ваш сервер, чтобы проверить это.

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js" type="text/javascript"></script> <title>Default Page</title> <script type="text/javascript""> $( document).ready( function() { $('#ajax_link').click( function() { var redirect_url = "/test.php"; $.ajax({ type: 'POST', url: "/test.php", data: {ajax : true}, dataType: "json", success: function( json) { if( json.redirect) { if( json.load_html) { // If the History API is available if( !(typeof history.pushState === 'undefined')) { history.pushState( { url: redirect_url, title: document.title}, document.title, // Can also use json.title to set previous page title on server redirect_url ); } document.open(); document.write( json.html); document.close(); } else { window.location = redirect_url; } } else { $('#message').html( json.message); } }, }); }) }); </script> </head> <body> <div id="message">The default contents of the message</div> <a id="ajax_link" href="#">Fire AJAX</a> </body> </html> 

Дайте id телу <body id="page"> а ваш другой div будет <div id="message"></div> теперь ваш аякс будет выглядеть так:

  $.ajax({ url:'myAjax.php', data:{datakey:datavalue}, dataType:"JSON", success: function (response) { if(response.message=="your message") { $('#message').html(response.content); } else { $('#page').html(response.content); } } }); 

как говорит T-Bull … весь процесс здесь неправильный ….

вы просто чрезмерно усложняете вещи, и вы знаете, что infact:

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

перестаньте усложнять и начинайте делать это хорошо …

  1. Клиент сначала открывает страницу, поэтому, отслеживайте ее $_SESSION['tmp_client_id'] = 'client_'.session_id(); очевидно, лучше, если клиент уже подписан, во всяком случае, помещает материал в временную таблицу ИЛИ в другой сеанс var и т. д. …
  2. Клиент заполняет форму;
  3. Клиент представляет форму;
  4. Сделайте запрос AJAX;
  5. Храните переменную $_POST внутри tmp_client_tbl с ее уникальным tmp_client_id ИЛИ просто $_SESSION['client_'.session_id()] = json_encode($_POST);
  6. Результат №1? отобразить сообщение в </div>
  7. Результат №2? обновить страницу и проверить if( isset($_SESSION['client_'.session_id()])) { если это так, давайте снова отобразим форму с заполненными полями: } else { отобразить пустую форму;
  8. SELECT * FROM tmp_client_tbl WHERE tmp_client_id = '{$_SESSION['tmp_client_id']}' ИЛИ json_decode($_SESSION['client_'.session_id()]);
  9. $form_data = $mysql_rows; ИЛИ $json_array;
  10. foreach($form_data as $name => $value) { echo "<input name='$name' value='$value' />" } в способе ниндзя, предполагающем, что у вас есть такой массив $form = array('text' => array('name','lastname'), 'select' => array('countries'), ... ) где $form = array('text' => array('name','lastname'), 'select' => array('countries'), ... ) , ИЛИ просто посредством <input name='lastname' value='{$lastname}' /> где значения полей предварительно распределены с пустыми vars;
  11. прошло время, произошла ошибка, браузер закрыт? session_destroy(); или unset($_SESSION['client_'.session_id()]);