关于重定向应如何工作的问题

时间:2011-04-23 00:26:29

标签: php forms codeigniter

所以我有一个网络应用程序,我正在处理一个表单,要求在提交之前填充所有字段。如果您尝试在没有填充字段的情况下提交应用程序,则会再次加载页面并显示错误。填写完所有字段并单击“提交”后,它会重定向到同一页面并显示从flashdata生成的消息。请参阅下面的简化示例。

欢迎控制器:

function show_view() 
{
  $this->load->view('form');
}

function process_form()
{
  // make the 'quality' field required
  $this->form_validation->set_rules('quality', 'Quality', 'required');

  if($this->form_validation->run() == FALSE) //if the fields are NOT filled in...
  {
    echo form_error('quality');
    $this->load->view('form'); //reload the page  
  }
  else  // if the fields are filled in...
  {
    // set success message in flashdata so it can be called when page is refreshed. 
    $this->session->set_flashdata('message', 'Your rating has been saved');
    redirect(welcome/show_view);
  }
}

现在说明我的问题,让我说我在'主页'视图,然后导航到'表单'视图。如果我填充“质量”字段并单击“提交”,我将被重定向回“表单”视图,并显示成功消息。如果我单击浏览器上的后退按钮,它会将我带回“主页”视图。一切按预期工作

现在让我说我在'主页'视图中,然后导航到'表单'视图。如果我单击提交按钮而不填充“质量”字段,则会再次重新加载“表单”视图并显示错误消息。如果我然后填充'质量'字段并单击提交,我将被重定向回到'表单'视图并显示成功消息。问题是,如果我单击浏览器上的后退按钮,它现在会将我带回到带有错误的表单页面,我必须再次单击后退按钮才能返回“主页”视图。

最好的编码实践是什么,以便如果用户提交有错误的表单,它将显示错误,如果他们修复错误并再次提交表单,它将显示成功消息,如果他们点击返回浏览器,它会将它们带回“主页”视图??

7 个答案:

答案 0 :(得分:3)

我希望表单能够将我重定向到资源列表页面,其中资源是用户最初提交的实体。

如果用户正在向资源添加新条目,则在表单成功提交后,他们希望在列表中看到该条目。

如果表单位于同一页面上,您仍应执行基于位置的重定向而不是http刷新。此用例的状态代码为 303 See Other

via Wikipedia HTTP 303 Status Code

以下是我根据您的情况做的事情。

function home(){
  $this->load->view('home');
}

function show_view() 
{
    $this->load->view('form');
}

function process_form()
{
    // make the 'quality' field required
    $this->form_validation->set_rules('quality', 'Quality', 'required');

 if($this->form_validation->run() === FALSE) //if the fields are NOT filled in...
 {
    echo form_error('quality');
    $this->load->view('form'); //reload the page  
 }
 else  // if the fields are filled in...
 {
    // set success message in flashdata so it can be called when page is redirected. 
    $this->session->set_flashdata('message', 'Your rating has been saved');
    redirect('welcome/home','location', 303);
    exit;
 }

}

答案 1 :(得分:3)

问题是您使用两个单独的函数来执行表单处理。表单验证类文档并没有真正解释它,我花了一些时间来实现它,但是如果有错误,form_validation-> run()返回false,但如果它是GET请求,则返回帐户对于相关函数中的GET请求,如form_error()和validation_errors(),set_value()等。

CI(以及一般情况下)的最佳做法是:

class Welcome extends CI_Controller{

function home(){
    $this->load->view('home');
}

function form() 
{
    // make the 'quality' field required
    $this->form_validation->set_rules('quality', 'Quality', 'required');

    // If the fields are NOT filled in...
    // or if there isn't a POST! (check the Form_validation.php lib to confirm)
    if ( $this->form_validation->run() === FALSE) 
    {
         // This form_error() function actually doesn't do anything if there 
         // wasn't a form submission (on a GET request)
         echo form_error('quality');
         $this->load->view('form'); // load or reload the page
    }
    else  // if the fields are filled in...
    {
         // set success message in flashdata so it can be 
         // called when page is redirected. 
         $this->session->set_flashdata('message', 'Your rating has been saved');
         redirect('welcome/home','location', 303);
         exit;
    }

}

然后在视图中的格式为action="welcome/form"

基本上所有的表单错误函数和与表单验证相关的所有东西都有检查以确定表单验证器是否实际运行...这里是一个来自表单助手文件中的form_error函数的示例

function form_error($field = '', $prefix = '', $suffix = '')
{
    if (FALSE === ($OBJ =& _get_validation_object()))
    {
        return '';
    }

    return $OBJ->error($field, $prefix, $suffix);
}

当它们不是POST时,它显示正常,并且具有您正在寻找的自然页面流。

与问题无关,但对表单验证类感到困惑/值得注意...如果您在参数字段中使用xss_clean,prep_url等过滤器,它实际上会为您重新填充$ _POST数组,所以你不要真的需要做任何额外的事情。

有时值得一看CI源的内部,有一些聪明的东西并不完全明显。

答案 2 :(得分:1)

我正在使用Symfony一段时间,我认为Symfony的解决方案是最佳的。它的工作方式是你有路由(我认为CI也有路由:CI routings)并且在你的控制器中你可以在你的“创建”方法中做这样的事情:

if the form is valid
  set flash notice message
  redirect to (your homepage or something else defined in your routing file)
else
  set flash error message
  set the current view to form

您的表单操作与具有“创建”操作的控制器相同(只能通过POST请求到达)。使用GET请求可以访问的表单是“新”方法。因此,如果单击表单上的“提交”,则转到create方法,但新方法首次生成表单。如果您的表单未验证,则会留下闪存错误消息。如果单击“返回”,则会显示一个新表单,但如果表单验证了您的操作(方法),则会重定向到之前在上述if语句中设置的自定义页面。

此方法也适用于ajax,如果请求是XHTTP,您可以检查您的操作,如果表单有效,您只需返回,并且您可以在javascript中处理。我认为这是处理表单的最佳方式,如果您的用户没有启用javascript,他仍然可以使用“标准”方式。顺便说一句:“创建”和“新”使用相同的模板(视图)。我希望我能说清楚。

答案 3 :(得分:1)

告诉浏览器在其历史记录中忽略/删除页面的唯一可靠方法是使用javascript命令:

location.replace(url);

这会进行客户端重定向,但会替换浏览器历史记录中的当前位置。或者根本不要去新页面(ajax调用)。

如果您使用POST作为表单中的方法,他们将收到错误消息,说他们必须重新提交信息到服务器才能返回,这会吓跑大多数人使用后退按钮。

您可以使用nonce模式生成时间戳或其他唯一ID,在创建表单时将其放在会话中以及show_view函数中的隐藏字段,然后在流程函数中检查它是否匹配,以及如果匹配,则将其从会话中删除。这样,如果他们尝试两次提交相同的表单(通过单击后退按钮),您可以通过查看没有匹配并将其重定向到无错误的show_view或主页或您想要的任何其他地方来检测它。

您还需要确保过期和缓存控制标头强制Web浏览器每次都使用其本地缓存来访问服务器。 http://www.web-caching.com/mnot_tutorial/notes.html#IMP-SERVER

对于下注者或更糟糕的是,大多数网站都会忽略后退按钮问题,例如这些

答案 4 :(得分:1)

DOM窗口对象通过历史记录对象提供对浏览器历史记录的访问。它公开了有用的方法和属性,使您可以在用户的​​历史记录中来回移动,以及 - 从HTML5开始 - 操作历史堆栈的内容。 https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history

另一件事是用ajax提交表单!并根据响应来填充错误或成功消息......(XML,JSON ..)当然这并不是你想要的,但它在用户体验方面有很多优点,这正是你想要改进的。

如果可能的话,请避免重定向,并让页面显示与重定向相同的内容。这样浏览器就不会将多个提交计为不同的页面。

此外,新的HTML5 javascript还有历史状态更改或其调用的任何内容。因此,您可以在程序中定义网站应如何通过后退按钮进行页面更改......很快您将看到很多后退按钮也集成到Web GUI中。

答案 5 :(得分:0)

执行您提议的最简单方法是使用HTTPRequest(AJAX)将表单值提交给PHP验证程序,然后使用JavaScript显示错误。这样您就不必进行任何重定向,后退按钮仍然会带您回家。

如果你坚持使用重定向,我会想到一些想法,但没有一个是优雅的。也许其他人对此有所了解?

虽然我真的建议使用AJAX表单提交作为此问题的解决方案。

答案 6 :(得分:0)

据我所知 - 并且可以找到 - 没有可靠的方法来捕获历史回溯事件,并且所有解决方案都是基于Javascript的,因此您可以构建一个AJAX表单。 我会说唯一可能的非JavaScript解决方案可能是iframe(没人喜欢),或BraedenP建议的。

就个人而言,如果你真的想要这个功能,我会构建一个AJAX表单,而不是让它对非JavaScript用户这样工作(他们应该习惯于稍微简化一点经验)。

在页面上添加痕迹痕迹或后退按钮总是很好的做法,所以这也有帮助。