HTTP Forward vs. Redirect

A Controller servlet may perform either a forward or a redirect operation at the end of processing a request. It is important to understand the difference between these two cases, in particular with respect to browser reloads of web pages.

Forward

  • a forward is performed internally by the application (servlet).
  • the browser is completely unaware that it has taken place, so its original URL remains intact
  • any browser reload of the resulting page will simple repeat the original request, with the original URL

Redirect

  • a redirect is a two step process, where the web application instructs the browser to fetch a second URL, which differs from the original
  • a browser reload of the second URL will not repeat the original request, but will rather fetch the second URL
  • redirect is marginally slower than a forward, since it requires two browser requests, not one
  • objects placed in the original request scope are not available to the second request.

There are several ways to perform a Redirect, here are a few common ones:

  • URL Redirection (HTTP 301):
    HTTP/1.1 301 moved permanently
    
    Location: http://www.example.org/
  • HTTP Refresh Header (Not Recommended)
    HTTP/1.1 200 ok
    
    Refresh: 0; url=http://www.example.com/
  • HTML <meta /> tag
    <meta http-equiv="refresh" content="0; URL=http://www.example.org/" />
  • JavaScript (many possible solutions, generally not accessible or searchable)
    <script type="text/javascript">location.href='http://www.example.org/';</script>

In general, a forward should be used if the operation can be safely repeated upon a browser reload of the resulting web page; otherwise, redirect must be used. Typically, if the operation performs an edit on the datastore, then a redirect, not a forward, is required. This is simply to avoid the possibility of inadvertently duplicating an edit to the database.

More explicitly :

  • for SELECT operations, use a forward
  • for INSERT, UPDATE, or DELETE operations, use a redirect

In HTML, a <FORM> tag can either GET or POST its data. In this context, a GET corresponds to a SELECT-then-forward, and a POST corresponds to an edit-then-redirect.

It is strongly recommended that forms for the input of search criteria should use GET, while forms for editing database records should use POST.

SECURITY NOTE: When using GET, be sure to not expose sensitive data in the URL’s.

Single FORM INPUT causes submit on Enter/Return

This is a browser oddity that I’ve had to code around for years.  In most modern browsers (currently Mozilla Firefox 2.x and MSIE 7.0), when a FORM contains only one editable INPUT field pressing the Enter or Return key will automatically submit the form, but when there are more than one the form is not submitted.   This irregularity in the single field case is responsible for several odd errors, and often results in double-submits of form data to the server.

Here’s a newer solution to the problem, the ‘magic’ is in the javascript events that we’ve added to the FORM object itself, no longer do you have to place event handlers on every INPUT field as has often been done in the past.

NOTE: not completely valid XHTML for ease of documentation and readability.

<html>
<head>
<title>test of input submit</title>
<script type=”text/javascript”>
function keycheckForm(formObj,evt){
if(isEnter(evt)){
//alert(‘in form’);
if(checkFormInputs(formObj)){
formObj.submit();
}
}
}
/*
* Added to handle enter key press
* NOTE: this is based on  a ‘legacy’ function [checkEnter(e)] that returned the reverse boolean values.
* @param evt Event
* @return boolean
*/
function isEnter(evt){ //e is event object passed from function invocation
var characterCode; //literal character code will be stored in this variable
if(evt && evt.which){ //if which property of event object is supported (NN4)
characterCode = evt.which; //character code is contained in NN4’s which property
}else{
characterCode = evt.keyCode; //character code is contained in IE’s keyCode property
}
var rc = false;
if(characterCode == 13){ //if generated character code is equal to ascii 13 (if enter key)
rc = true;
}
return rc;
}
/**
* @param formObj Object
*/
function checkFormInputs(formObj){
var rc = false;
var allInputs=formObj.getElementsByTagName(‘INPUT’);
var formInputs = allInputs.length;
var textInputs=0;
if(formInputs>1){
var ct = allInputs.length;
var i;
for(i=0; i < ct; i++){
var inputObj = allInputs[i];
var typ = inputObj.type;
if ((typ==’text’) || (typ==’password’)) {
textInputs=textInputs+1;
}
}
if(textInputs>1){
rc=true;
}
}
if(rc==false){
//alert(“blocked because of size”);
}
return rc;
}
</script>
</head>
<body>
<form action=”example.php” method=”get” onkeypress=”return keycheckForm(this,event);” onsubmit=”return checkFormInputs(this);”>
<input type=”text” name=”textfield1″ value=”testing1″ />
<button type=”button” name=”mybutton” onclick=”this.form.submit();”>Click Me</button>
</form>
</body>
</html>

Cheers!