If-None-Match header after a 302 redirection in Internet Explorer 11

1k views Asked by At

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:

Firefox - Network tab

Chrome:

Chrome - Network tab

Internet Explorer 11:

IE 11 - Network tab

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 and Cache-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.

IE 11 - Network tab

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.

0

There are 0 answers