我们正在使用ETag
和If-None-Match
headers 来提高单页应用程序在初始加载时的性能。我注意到,当服务器发送重定向(303 或 302)时,Internet Explorer 的反应方式与 Firefox 和 Chrome 不同。
观察:
当服务器为给定页面发送 302 代码以指示应重新加载页面时(位置标头指向同一页面)。然后 IE 使用它的缓存版本(它发送If-None-Match
并获得 304 答案),Firefox 和 Chrome 认为应该重新加载页面。
使用一个简单的服务器,该服务器始终发送相同的页面(具有弱ETag
值),除了将重定向(302 代码)发送到同一页面的每个 fith 响应。
火狐:
铬合金:
互联网浏览器 11:
问题:
这是预期的行为吗?是否有可能强制 IE 重新加载页面?
错误的解决方案:
根据我在 StackOverflow 上阅读的答案:
我曾尝试发送Expires
,Cache-Control
当我发送 302 重定向请求时,IE 会:
- 用户请求 (F5),响应是带有标头的 302 代码
Expires: -1
和Cache-Control: must-revalidate, private
- 请求跟随重定向,请求带有 header
If-None-Match
,响应是一个 304 代码。 - 用户请求 (F5),没有标头
If-None-Match
,响应是 200 代码。
实验代码:
我改编了Jetty Hello-World示例:
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>
<groupId>org.eclipse.jetty.aggregate</groupId>
<artifactId>jetty-all</artifactId>
<version>9.3.6.v20151106</version>
<type>pom</type>
</dependency>
背景:
这个例子真的很简约。在我们的生产环境中,302 重定向是由登录模块生成的。问题是有时,IE 只是显示一个白色窗口而不是页面内容。