We are using ETag
and If-None-Match
headers to improve the performances of our Single Page Application on the initial load.
I have noticed that Internet Explorer do not react the same way than Firefox and Chrome when a redirection (303 or 302) is send by the server.
Observation:
When a Server sends for a given page a 302 Code to indicate that the page should be reloaded (the location header points to the same page). Then IE use its cached version (it sends the If-None-Match
and get the 304 answer) where Firefox and Chrome consider that the page should be reloaded.
With a simple server that sends always the same page (with a weak ETag
value) except each fith response where it send a redirection (302 code) to the same page.
Firefox:
Chrome:
Internet Explorer 11:
Question:
Is this an intended behavior? Is there a possibility to force IE to reload the page?
Wrong solution:
Based on the answers I have read on StackOverflow:
I have tried to send Expires
and Cache-Control
when I send my 302 redirect request, but then IE does:
- User Request (F5), response is a 302 code with headers
Expires: -1
andCache-Control: must-revalidate, private
- Request to follow the redirection, request with header
If-None-Match
, response is a 304 code. - User Request (F5), without header
If-None-Match
, response is a 200 code.
Code for the experiment:
I have adapted the Jetty Hello-World example:
package org.eclipse.jetty.embedded;
import java.io.IOException;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;
public class JettyHelloWorld extends AbstractHandler {
public static final String IF_NONE_MATCH = "If-None-Match"; //$NON-NLS-1$
long time = new Date().getTime();
int counter = 0;
@Override
public void handle(String target,
Request baseRequest,
HttpServletRequest request,
HttpServletResponse response) throws IOException,
ServletException {
String etag = createEtag();
String ifNoneMatch = request.getHeader(IF_NONE_MATCH);
boolean clientSentEtag = (ifNoneMatch != null);
counter = counter + 1;
System.out.print("[" + (counter % 5) + "]");
if (counter % 5 == 0) {
System.out.println("SEND 302 for " + request.getPathInfo());
// response.setHeader("Expires", "-1");
// response.setHeader("Cache-Control", "must-revalidate, private");
response.setHeader("Location", "/");
response.setStatus(HttpServletResponse.SC_FOUND);
// response.sendRedirect("/");
baseRequest.setHandled(true);
} else if (clientSentEtag && notModified(ifNoneMatch, etag)) {
// Check If-None-Match (Etag)
System.out.println("SEND 304 for " + request.getPathInfo());
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
baseRequest.setHandled(true);
} else {
System.out.println("SEND 200 for " + request.getPathInfo());
response200(baseRequest, response);
}
}
private void response200(Request baseRequest, HttpServletResponse response) throws IOException {
// Declare response encoding and types
response.setContentType("text/html; charset=utf-8");
response.addHeader("ETag", createEtag());
// Declare response status code
response.setStatus(HttpServletResponse.SC_OK);
// Write back response
response.getWriter()
.println("<h1>Hello World:" + time + "</h1>");
// Inform jetty that this request has now been handled
baseRequest.setHandled(true);
}
private String createEtag() {
return "W/\"" + time + "\"";
}
private boolean notModified(String ifNoneMatch, String etag) {
return (ifNoneMatch != null && etag != null && ifNoneMatch.indexOf(etag) != -1);
}
public static void main(String[] args) throws Exception {
Server server = new Server(8080);
server.setHandler(new JettyHelloWorld());
server.start();
server.join();
}
}
Dependency:
<dependency>
<groupId>org.eclipse.jetty.aggregate</groupId>
<artifactId>jetty-all</artifactId>
<version>9.3.6.v20151106</version>
<type>pom</type>
</dependency>
Background:
This example is really minimalistic. In our productive environment, the 302 Redirect is produced by the login module. The problem is that sometimes, IE is just displaying a white window instead of the page content.