更新Ajax请求的整个页面

时间:2011-05-09 20:08:39

标签: php javascript jquery ajax http

我有一个可能有两种可能结果的AJAX请求:

  1. 服务器回复一条消息,我应将其放在<div>
  2. 服务器以HTML页面响应,在这种情况下,我需要用新的页面替换当前页面并更改地址(客户端在请求之前知道地址)。
  3. 如果我有需要处理这两种情况的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 个答案:

答案 0 :(得分:28)

坦率地说,我认为这种方法基本上被设计破坏了。你不应该在那个地方做出那个决定。例如,ajax响应只能表示应该加载整个新页面,然后在对新URL的第二个(非ajax)请求上生成新内容。

如果你被迫采取你已经采取的方式,并且如果响应内容不是很大,你可以试试Javascript-URIs。基本上,javascript:"string"形式的URI将加载一个新页面,该页面是该字符串的源代码。因此,如果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。

<强>更新

类似的方法是在数据URI中使用base64编码。 Wikipedia entry解释了它的工作原理,包括一个javascript示例。但是,您必须以某种方式base64-encode内容。 (注意:您可以使用带或不带base64编码的数据URI。您必须查看为您的特定内容提供更短URI的原因。)

答案 1 :(得分:10)

我有一次类似的问题。返回了完整的错误页面,而不是简单的HTML代码段。我们最终通过改变逻辑来解决这个问题,但这是我找到的解决方案之一:

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

我们放弃这个的原因是在IE上存在一些问题。我没有随时调查原因,但在尝试编写字符串时它抛出了“拒绝访问”异常。我认为有一些<meta>标签混淆了IE,或者条件评论,我不确定。 (当我使用一些简单的页面时它起作用了......)

底线是:你不应该这样做,但如果你没有其他任何东西可以做(比如返回一个url字符串),上面的代码可能会起作用。

答案 2 :(得分:5)

如果响应是有效的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);

答案 3 :(得分:4)

由于请求是针对更新的答案,因此我的解决方案是使用HTML5的History APIjQuery。它应该通过将PHP和HTML部分组合到一个文件中来轻松运行。

我的解决方案允许AJAX返回以下内容:

  1. 通过AJAX发送的消息,用于更新<div>容器。
  2. 导致浏览器重定向到网址的网址
  3. 一个完整的HTML页面,它调用History API的history.pushState()将当前URL添加到浏览器的历史记录中,并使用从AJAX返回的HTML替换页面上的整个HTML。
  4. PHP

    这只是PHP脚本在通过AJAX调用时需要返回的示例。它显示了如何编码标志以确定AJAX调用是应该更新容器还是加载新页面,以及如何通过json_encode通过JSON返回其结果。为了完整起见,我将此脚本命名为 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,以及URL test.php 上面的PHP脚本。请注意,它还将POST参数ajax设置为true,从而使PHP脚本能够检测到它收到了AJAX请求。 dataType字段告诉jQuery服务器的响应将是JSON,并且它应该将JSON解码为响应回调中的JSON对象。最后,成功接收到AJAX响应时触发的success回调根据服务器发送的标志确定要执行的操作。

    $.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>
    

答案 4 :(得分:1)

为正文<body id="page">提供ID,而您的其他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);   
           }
      }
     });

答案 5 :(得分:0)

正如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. 中显示消息
  8. 结果#2?刷新页面并检查if( isset($_SESSION['client_'.session_id()])) {如果是这样,让我们​​再次使用填充字段显示表单:} else {显示空表单;
  9. SELECT * FROM tmp_client_tbl WHERE tmp_client_id = '{$_SESSION['tmp_client_id']}'json_decode($_SESSION['client_'.session_id()]);
  10. $form_data = $mysql_rows;$json_array;
  11. 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}' />,其中字段值是用空的vars预先校正的; < / LI>
  12. 时间已过,发生错误,浏览器已关闭? session_destroy();unset($_SESSION['client_'.session_id()]);