根据 Ajax 请求更新整个页面

发布于 2024-11-05 20:37:24 字数 658 浏览 1 评论 0原文

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

  1. 服务器响应一条消息,我应将其放入
  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 响应一样处理响应并更新页面位置和内容,例如使用给定内容进行重定向。

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

I have an AJAX request that can have two possible outcomes:

  1. The server responds with a message which I should place in a <div>
  2. The server responds with an HTML page, in this case I need to substitute current page with a new one and change the address (the client knows the address before a request).

What would be the solution if I have the AJAX request that needs to handle both of these cases?

 url = "http://example.com"
 ajax.request(callback)

 function callback(response) {
     if (case2(response)) {
           history.pushState({}, "New page", url);
           document.innerHTML = response
     } else {
            updateDiv(response)
     }
 }

I'm interested in a correct way to implement the first branch, or if the server can somehow compose a headers that will make browser to handle a response as a usual HTTP response and update a page location and content, something like redirect with given content.

I understand that the server can return a link instead of a page, but in this case one additional stage will be needed on a client - redirect and then populating the new page on the server.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

脸赞 2024-11-12 20:37:24

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

如果您被迫采用已经采取的方式,并且响应内容不是很大,您可以尝试 Javascript-URI。基本上,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 编码。 维基百科条目解释了它的工作原理,包括一个 JavaScript 示例。但是,您必须对内容进行 base64 编码不知何故。 (注意:您可以使用带或不带 base64 编码的数据 URI。您必须了解什么可以为您的特定内容提供更短的 URI。)

Quite frankly, I think that approach is basically broken by design. You shouldn't have to make that decision at that place. For example, the ajax response could only signal that a whole new page should be loaded and the new content then be generated on a second (non-ajax) request to a new URL.

In case you're forced to take the way you already go, and provided the response content is not very large, you could try Javascript-URIs. Basically, an URI in the form of javascript:"string" will load a new page which that string is the source code for. So, if response already is a string, just assigning javascript:response to window.location.href should suffice. Maybe you have to do some escaping beforehand. And I don't know, how cross-browser-compatible this approach is.

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

is also possible.

A variant of this is building the URL not with the variable name, but with the actual string data. Like

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);

This will, of course, generate pretty large URIs. And you'll always have the Javascript-URI in the address bar.

UPDATE

A similar approach is to use base64 encoding in a data URI. The Wikipedia entry explains how it works, including a javascript example. However, you'd have to base64-encode the content somehow. (Note: You can use data URIs with or without the base64 encoding. You have to see what gives you shorter URIs for your specific content.)

忱杏 2024-11-12 20:37:24

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

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

我们放弃这个的原因是 IE 上存在一些问题。我没有浪费任何时间来调查原因,但在尝试写入字符串时它引发了“访问被拒绝”异常。我认为有一些 标签使 IE 感到困惑,或者可能是条件注释,我不确定。 (当我使用一些简单的页面时,它起作用了......)

底线是:您不必这样做,但如果您无能为力(例如返回 url 字符串),则上面的代码可能会起作用。

I had a similar issue once. A full error page was returned instead of a simple HTML snippet. We eventually fixed this by changing the logic, but here is one of the solutions I found:

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

The reason we abandoned this is that on IE there were some problems. I didn't loose any time to investigate why, but it threw an 'Access denied' exception when attempting to write the string. I think there were some <meta> tags that confused IE, or maybe conditional comments, I'm not sure. (It worked when I used some simple pages...)

Bottom line is: you shouldn't have to do this, but if there is nothing else you can do (like returning an url string) the code above might work.

情绪少女 2024-11-12 20:37:24

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

It's really easy if the response is valid 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);
养猫人 2024-11-12 20:37:24

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

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

  1. 通过 AJAX 的消息,更新
    容器。
  2. URL,导致浏览器重定向到该 URL
  3. 完整的 HTML 页面,调用 History API 的 history.pushState() 将当前 URL 添加到浏览器的历史记录中,并替换浏览器上的整个 HTML包含从 AJAX 返回的 HTML 的页面。

PHP

这只是 PHP 脚本通过 AJAX 调用时需要返回的示例。它展示了如何对标志进行编码以确定 AJAX 调用是否应该更新容器或加载新页面,以及如何通过

<?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>

Since the request is for an updated answer, here's my solution using HTML5's History API with jQuery. It should run easily by combining the PHP and HTML parts into one file.

My solution allows for AJAX to return the following:

  1. A message through AJAX, which updates a <div> container.
  2. A URL, which causes the browser to redirect to the URL
  3. A complete HTML page, which calls the History API's history.pushState() to add the current URL to the browser's history and replaces the entire HTML on the page with the HTML returned from AJAX.

PHP

This is just a sample of what the PHP script will need to return when it is invoked via AJAX. It shows how to encode flags to determine whether the AJAX call should update the container or load a new page, and how to return its result via JSON through json_encode. For completeness, I named this script 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

Since I am using jQuery, lets start with that. The following submits an AJAX POST to the server, to the above PHP script at URL test.php. Note that it also sets the POST parameter ajax to be true, enabling the PHP script to detect that it received an AJAX request. The dataType field tells jQuery that the server's response will be in JSON, and that it should decode that JSON to a JSON object in the response callback. Finally, the success callback, which is fired when the AJAX response is successfully received, determines what to do based on the flags sent from the server.

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

Here is the complete HTML source of my tested file. I tested it in FF4 - FF8. Note that jQuery provides the ready method to prevent the JS from executing until the DOM is loaded. I've also used Google's hosting of jQuery, so you do not need to upload a copy of jQuery to your server to test this.

<!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>
酒几许 2024-11-12 20:37:24

给 body 一个 id,你的另一个 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);   
           }
      }
     });

Give an id to body <body id="page"> and your other div will be <div id="message"></div> now your ajax will look like

 $.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);   
           }
      }
     });
一身骄傲 2024-11-12 20:37:24

正如 T-Bull 所说...整个过程在这里都是错误的...

您只是将事情过于复杂化了,而且您实际上知道:

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

停止复杂化并开始做好...

  1. 客户端第一次打开页面,因此,跟踪它 $_SESSION['tmp_client_id'] = 'client_'.session_id(); 如果客户端已经订阅了,无论如何,将内容放入临时表或另一个会话变量等中...
  2. 客户填写表格;
  3. 客户提交表格;
  4. 发出 AJAX 请求;
  5. $_POST 变量存储在 tmp_client_tbl 中,并使用其唯一的 tmp_client_id 或仅 $_SESSION['client_'.session_id()] = json_encode( $_POST);
  6. 结果 #1 ?在
  7. 结果 #2 中显示消息?刷新页面并检查 if( isset($_SESSION['client_'.session_id()])) { 如果是这样,让我们​​再次显示带有填充字段的表单: } else {显示空表格;
  8. 从 tmp_client_tbl 中选择*,其中 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 "<输入 name='$name' value='$value' />" } 以忍者的方式假设您有这样一种表单构建器数组,其中 $form = array('text' => array('name','lastname'), 'select' => ; array('countries'), ... ),或者简单地通过 其中字段值已被空预污染变量;
  11. 时间已过、发生错误、浏览器已关闭? session_destroy();unset($_SESSION['client_'.session_id()]);

as T-Bull say... the whole process is wrong here....

you simply are over-complicating things and you know that infact:

I understand that the server can return a link instead of a page, but
in this case one additional stage will be needed on a client -
redirect and then populating the new page on the server.

stop complicating and start do it well...

  1. Client open the page first time, so, track it $_SESSION['tmp_client_id'] = 'client_'.session_id(); obviously is better if the client is already subscribed, anyway, put stuff in temp table OR into another session var etc...
  2. Client fill in the form;
  3. Client submit the form;
  4. Make the AJAX request;
  5. Store $_POST variable inside tmp_client_tbl with it's unique tmp_client_id OR just $_SESSION['client_'.session_id()] = json_encode($_POST);
  6. Outcome #1 ? display message in a </div>
  7. Outcome #2 ? refresh page and check if( isset($_SESSION['client_'.session_id()])) { if so let's display the form again with filled fields: } else { display empty form;
  8. SELECT * FROM tmp_client_tbl WHERE tmp_client_id = '{$_SESSION['tmp_client_id']}' OR json_decode($_SESSION['client_'.session_id()]);
  9. $form_data = $mysql_rows; OR $json_array;
  10. foreach($form_data as $name => $value) { echo "<input name='$name' value='$value' />" } in a ninja way that assume you have such kind of form builder array where $form = array('text' => array('name','lastname'), 'select' => array('countries'), ... ), OR simply by <input name='lastname' value='{$lastname}' /> where the fields values are pre-polutated with empty vars;
  11. time elapsed, error occurred, browser closed? session_destroy(); or unset($_SESSION['client_'.session_id()]);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文