我有一个带有表单的网页。当用户提交表单时,我希望服务器使浏览器重定向到与表单操作不同的页面。现在,我正在通过使用PHP的标头函数发送302状态代码来做到这一点。工作正常。
我试图使服务器上的页面以相同的方式重定向浏览器,而不管它是正常提交??(不使用Javascript)还是通过Ajax提交。我试图通过将窗口位置设置为Location标头中的任何URL来完成此操作。我正在使用jQuery,并进行如下调用:
$.ajax({
url: this.action,
type:"POST",
data: getFormData(this),
complete: function(request) {
window.location.assign(request.getResponseHeader("Location"));
}
});
但是,那没有用。考虑了一下,我意识到这并不奇怪。在Ajax请求中,浏览器应该在更改readyState之前透明地处理重定向响应(例如302代码)。当complete函数运行时,它正在最终目的地中寻找Location标头,而没有找到它。
作为实验,我然后尝试发送带有位置标头的200状态代码。我尝试了Ajax请求,它运行良好。但是,当我执行非Ajax提交时,它没有用。浏览器转到表单操作页面并停留在那里,就像它忽略了Location标头一样。
在这两种情况下,是否有任何方法可以使同一页面重定向,而服务器不必知道或不在乎该请求是否为Ajax请求?
万一这很重要,我每次都在各种浏览器(IE8,IE7,IE6,Firefox 3.5,Chrome)中尝试过该表单,但结果相似。另外,我正在进行发布请求,以避免碰到IE的2083个字符的URL长度限制。
XmlHttpRequest实现(例如jQuery的ajax函数)以静默方式使用HTTP 302响应。这是一个功能。
我过去解决此问题的方法是检测XmlHttpRequests并发出"Content-Location"标头(而不是"Location"标头)。最跨库的方法是检查服务器端代码中的"X-Requested-With" http标头(jQuery,Prototype,Mootools等设置此标头):
if (@$_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
header('Content-Location: ' . $redirect_url);
} else {
header('Location: ' . $redirect_url);
}
您仍然需要对客户端代码进行特殊处理:
$.ajax({
// ...
complete: function(xhr) {
var redirect_url = xhr.getResponseHeader("Content-Location");
if (redirect_url) {
window.location = redirect_url;
}
}
})
这是另一个选项,尽管您需要进行一些跨浏览器测试:
complete: function(request) {
if(request.status == 200) {
var doc = document.open(request.getResponseHeader('Content-Type'));
doc.write(request.responseText);
doc.close();
}
}
主要缺点:地址栏中的URL不变。可能会后退按钮/历史混乱
尽管我认为@crescentfresh的想法是必经之路
Havent很久没见过document.open()了。该代码只是要完全擦除当前页面,不是吗?有趣...
是的,它只是将页面替换为responseText。在Firefox和Safari上,它也会触发onload事件,还没有在其他浏览器上尝试过。使您不必再请求已拥有的资源。
为什么不让您的" ajax操作"简单地填写所需的表单字段并提交表单呢?这样,您将获得与手动提交时完全相同的行为。
您是否尝试使用错误功能而不是完整功能?
$.ajax({
url: this.action,
type:"POST",
data: getFormData(this),
error: function(request) {
if(request.status == 302)
window.location.assign(request.getResponseHeader("Location"));
}
});
jQuery向错误函数发送任何3xx响应。也许"位置"标头在此阶段仍然可用。
我尝试了类似的方法,但没有成功。它不应该那样工作。浏览器在有机会运行完整,成功或错误功能之前,应该透明地遵循302代码。有关更多详细信息,请参见我以前的评论(stackoverflow.com/questions/373087/)。
我懂了。看来您需要针对ajax做出不同的答复。真痛
将"完成"工作:
$.ajax({
type: frm.attr('method'),
url: frm.attr('action'),
data: frm.serialize(),
complete: complete(xhr, status) {
window.location.assign(xhr.getResponseHeader("Location"));
}
});
它适用于200响应,但不适用于302响应。阅读我的文章以了解更多详细信息。
将其他参数传递给您的ajax请求,以轻松识别请求的类型。当ajax-不重定向-只需发送目标URL,然后通过location.href在ajax回调中重定向客户端
像这样:
$.post('/controller/action', {formdata}, function (redirect_to) {
location.href = redirect_to;
});
我想进一步了解您的用例。据我了解,您试图让您的应用程序根据其中的Ajax调用的"位置"标头加载页面吗?我问为什么?
HTTP标头似乎不是从中获取该信息的正确位置。您的应用程序本质上不是在查询"我应该重定向到哪里吗?"。没有理由,Ajax响应实际上必须响应302和" Location"标头。为什么不让它使用包含新URL的JSON或XML进行响应?
编辑:只需重新阅读您的倒数第二段。我不确定是否有实现您想要的好方法。这个概念对我来说听起来很糟。 :)
如果用户无论如何都被重定向,为什么要使用Ajax?这样的Ajax的全部目的是在不刷新页面的情况下对页面进行更改,因此您所使用的技术似乎有点像构建一台输出到切碎斗中的打印机。
也许如果有错误就没有重定向,例如验证类型的东西
好问题。服务器上的同一脚本由不同页面上的许多表单使用,其中一些表单的设计不正确,因此没有充分的理由尝试使用Ajax提交。在我可以修复这些表格之前,这可能是一个临时的解决方法。另外,我很好奇是否可以做到这一点,因为有一天可能会派上用场。我可能想让我的网站在某些方面使用Ajax,但仍可用于不支持Javascript的客户端。另外,根据服务器的决定,我可能需要发出Ajax请求,并停留在同一页面上或重定向。