我有一个可能有两种可能结果的AJAX请求:
<div>
如果我有需要处理这两种情况的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响应处理并更新页面位置和内容,例如重定向给定内容。
我理解服务器可以返回链接而不是页面,但在这种情况下,客户端需要一个额外的阶段 - 重定向然后在服务器上填充新页面。
答案 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 API和jQuery。它应该通过将PHP和HTML部分组合到一个文件中来轻松运行。
我的解决方案允许AJAX返回以下内容:
<div>
容器。history.pushState()
将当前URL添加到浏览器的历史记录中,并使用从AJAX返回的HTML替换页面上的整个HTML。这只是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;
}
由于我使用的是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源代码。我在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)
你只是过于复杂化了事情而且你知道事实:
我知道服务器可以返回链接而不是页面,但是 在这种情况下,客户需要一个额外的阶段 - 重定向然后在服务器上填充新页面。
停止复杂化并开始做好......
$_SESSION['tmp_client_id'] = 'client_'.session_id();
显然更好,如果客户端已经订阅了,无论如何,将内容放入临时表或其他会话var等...... $_POST
变量存储在tmp_client_tbl
内,其唯一tmp_client_id
或$_SESSION['client_'.session_id()] = json_encode($_POST);
</div>
if( isset($_SESSION['client_'.session_id()])) {
如果是这样,让我们再次使用填充字段显示表单:} else {
显示空表单; SELECT * FROM tmp_client_tbl WHERE tmp_client_id = '{$_SESSION['tmp_client_id']}'
或json_decode($_SESSION['client_'.session_id()]);
$form_data = $mysql_rows;
或$json_array;
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>
session_destroy();
或unset($_SESSION['client_'.session_id()]);