Обновить всю страницу по запросу Ajax - PullRequest
29 голосов
/ 10 мая 2011

У меня есть запрос 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-ответ и обновлять местоположение и содержимое страницы, что-то вроде перенаправления с данным содержимым.

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

Ответы [ 6 ]

28 голосов
/ 12 мая 2011

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

В случае, если вы вынужденычтобы пойти тем же путем, и если содержание ответа не очень велико, вы можете попробовать Javascript-URI.По сути, URI в форме javascript:"string" загрузит новую страницу, для которой эта строка является исходным кодом.Таким образом, если response уже является строкой, достаточно присвоить javascript:response 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 в адресной строке.

UPDATE

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

10 голосов
/ 10 мая 2011

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

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

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

Суть в следующем: вам не нужно этого делать, но если нет ничего другого, что вы можете сделать (например, вернуть строку URL), кодвыше может работать.

5 голосов
/ 17 мая 2011

Это действительно легко, если ответ правильный 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);
4 голосов
/ 06 декабря 2011

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

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

  1. Сообщение через AJAX, которое обновляет <div> container.
  2. URL-адрес, который заставляет браузер перенаправить на URL-адрес
  3. Полная HTML-страница, которая вызывает API-интерфейс History * 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 в ответном обратном вызове.Наконец, обратный вызов 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>
1 голос
/ 09 мая 2015

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

 $.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);   
           }
      }
     });
0 голосов
/ 07 декабря 2011

как говорят T-Bull ... весь процесс здесь не так ...

Вы просто слишком усложняете вещи и знаете, что это за факт:

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

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

  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'), ... ), ИЛИ просто на <input name='lastname' value='{$lastname}' />, где значения полей предварительно полулируются пустыми переменными;
  11. истекло время, произошла ошибка, браузер закрыт? session_destroy(); или unset($_SESSION['client_'.session_id()]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...