更新Ajax请求的整个页面

Nut*_*tel 29 javascript php ajax jquery http

我有一个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)
     }
 }
Run Code Online (Sandbox Code Playgroud)

我感兴趣的实施首支以正确的方式,或者服务器可以以某种方式组成一个头,这将使浏览器处理,因为通常的HTTP响应的响应和更新网页的位置和内容,类似与给定的内容重定向.

我知道服务器可以返回链接而不是页面,但在这种情况下,客户端将需要一个额外的阶段 - 重定向,然后在服务器上填充新页面.

T-B*_*ull 28

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

如果你被迫采取你已经采取的方式,并且如果响应内容不是很大,你可以试试Javascript-URIs.基本上,形式的URI javascript:"string"将加载一个新页面,该字符串是该源代码的源代码.所以,如果response已经是一个字符串,只需分配javascript:responsewindow.location.href足够了.也许你必须事先做一些逃避.我不知道,这种方法与跨浏览器兼容的方式如何.

<a href="javascript:response">load</a>
Run Code Online (Sandbox Code Playgroud)

也是可能的.

这种方法的一个变体是不使用变量名构建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);
Run Code Online (Sandbox Code Playgroud)

当然,这将生成相当大的URI.而且你总是在地址栏中有Javascript-URI.

UPDATE

类似的方法是在数据URI中使用base64编码.在维基百科条目解释它是如何工作的,包括一个javascript例子.但是,您必须以某种方式对内容进行base64编码.(注意:您可以使用带或不带base64编码的数据URI.您必须查看为您的特定内容提供更短URI的内容.)


Dan*_*anu 10

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

document.open();
document.write(responseText);
document.close();
Run Code Online (Sandbox Code Playgroud)

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

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


Eli*_*rey 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);
Run Code Online (Sandbox Code Playgroud)


nic*_*ckb 5

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

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

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

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;
}
Run Code Online (Sandbox Code Playgroud)

JS

由于我使用的是 jQuery,让我们从它开始。下面将 AJAX POST 提交到服务器,到 URL test.php的上述 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);
        }
    },
});
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)