【问题标题】:far future Expires header for static contents静态内容的远期过期标头
【发布时间】:2013-02-15 20:30:47
【问题描述】:

这里怎么写http://developer.yahoo.com/performance/rules.html

对于静态组件:通过设置远期 Expires 标头来实施“永不过期”策略

我可以避免使用响应为“304”的 http 请求来获得性能。
在正式比赛中!文档我可以看到如何设置缓存控制指令,但是如何设置远期的 Expires 标头?

最好的问候尼古拉


编辑:感谢重播,现在它也可以正常工作了!这里有类:

配置/路由

  # Static files
  GET /assets/stylesheets/img/:name controllers.StaticFilesController.getBoostrapImg(name)
  GET /assets/images/*name          controllers.StaticFilesController.getImg(name)
  GET /assets/stylesheets/*name     controllers.StaticFilesController.getCss(name)
  GET /assets/javascripts/*name     controllers.StaticFilesController.getJs(name)


控制器/StaticFilesController.java

package controllers;
import org.apache.http.impl.cookie.DateUtils;
import java.util.*;
import play.mvc.*;
import services.FileName;
import play.*;
public class StaticFilesController extends Controller {

private static String nextYearString = StaticFilesController
        .getNextYearAsString();

public static Result getImg(String path) {

    FileName fileName = new FileName(path);
    response().setHeader(EXPIRES, nextYearString);
    response().setContentType("image/" + fileName.extension());
    return ok(Play.application().getFile("/public/images/" + path));
}

public static Result getBoostrapImg(String path) {

    FileName fileName = new FileName(path);
    response().setHeader(EXPIRES, nextYearString);
    response().setContentType("image/" + fileName.extension());
    return ok(Play.application().getFile(
            "/public/images/" + fileName.filename() + "."
                    + fileName.extension()));
}

public static Result getCss(String path) {

    response().setHeader(EXPIRES, nextYearString);
    response().setContentType("text/css");
    return ok(Play.application().getFile("/public/stylesheets/" + path));
}

public static Result getJs(String path) {

    response().setHeader(EXPIRES, nextYearString);
    response().setContentType("application/x-javascript");
    return ok(Play.application().getFile("/public/javascripts/" + path));
}

private static String getNextYearAsString() {
    Calendar calendar = new GregorianCalendar();
    calendar.add(Calendar.YEAR, 1);
    return DateUtils.formatDate(calendar.getTime());
}
}


services/FileName.java

package services;

/**
* This class assumes that the string used to initialize fullPath has a
* directory path, filename, and extension. The methods won't work if it
* doesn't.
*/
public class FileName {
private String fullPath;
private char pathSeparator, extensionSeparator;

public FileName(String str, char sep, char ext) {
 fullPath = str;
 pathSeparator = sep;
 extensionSeparator = ext;
}

public FileName(String str)
{
  fullPath = str;
  pathSeparator = '/';
  extensionSeparator = '.';
}

public String extension() {
  int dot = fullPath.lastIndexOf(extensionSeparator);
  return fullPath.substring(dot + 1);
 }

 public String filename() { // gets filename without extension
 int dot = fullPath.lastIndexOf(extensionSeparator);
 int sep = fullPath.lastIndexOf(pathSeparator);
  return fullPath.substring(sep + 1, dot);
}

 public String path() {
  int sep = fullPath.lastIndexOf(pathSeparator);
   return fullPath.substring(0, sep);
  }
 }


views/main.scala.html

 @(skin: String)(content: Html)

 <!DOCTYPE html>

 <html lang="en">
   <head>
     <meta charset="utf-8"> 
     <title>LibreTitan</title>
      <link rel="stylesheet" media="screen"    href="@routes.StaticFilesController.getCss("bootstrap/bootstrap.min.css")">
    @if(skin != null && !skin.equals("")) {
    <link rel="stylesheet" media="screen" href="@routes.StaticFilesController.getCss(skin+".min.css")">
    }
    <link rel="shortcut icon" type="image/png" href="@routes.StaticFilesController.getImg("favicon.png")">
    <script async src="@routes.StaticFilesController.getJs("jquery-1.9.0.min.js")"></script>
    <script async src="@routes.StaticFilesController.getJs("bootstrap.min.js")"></script>
</head>
<body>
    <div class="container">
        @content
     </div>
    </body>
 </html>

【问题讨论】:

    标签: playframework-2.1


    【解决方案1】:

    Never expire 在此上下文中的策略意味着应将 Expire 标头添加到您的响应中,该日期是在很远的将来,例如从现在开始的 10 年。您可以按照Manipulating the response 文档中的说明在 Play 中轻松完成此操作。示例:

    public static Result index() {
        response().setHeader(EXPIRES, "Thu, 16 Feb 2023 20:00:00 GMT");
        return ok("<h1>Hello World!</h1>");
    }
    

    当然,而不是将过期日期作为 String,您应该使用某种方法来动态计算它,您可以使用 org.joda.time.DateTime(在 Play 中可用)及其方法,例如:plusYears(int years)。最重要的是最后应该格式化为RFC 1123日期格式。

    编辑,当然您可以返回不同类型的结果 - 也可以返回二进制,如 doc(“结果”部分)中所述,检查所有可用选项查看 API:@987654324 @ 可以是:ok(Content content) - 渲染某些视图时的典型值,ok(java.io.File content)ok(java.io.InputStream content) 等。

    另一方面...

    我绝对建议不要使用 Play 来提供 far future static contents(以及任何其他静态、公共内容)。尽管您可以轻松地做到这一点,但如上所述,恕我直言,这是对 Play 资源的多余浪费,因为您需要处理对任何单个图像、脚本、样式...的所有请求。

    考虑为该工作使用通用的... HTTP 服务器(nginx、lighthttpd、Apache),甚至更好的一些分布式 CDN。在这种情况下,您的应用可以关注执行其逻辑,而不是在磁盘上搜索样式表。

    P.S. 请记住,如果您使用的是 Play 而不是 HTTP 服务器,则要添加从 /public 文件夹提供的新静态内容,您需要重新启动应用程序,因此至少使确保将它们保存在应用程序之外的某个专用文件夹中,这样您就可以在不停止应用程序的情况下添加/删除/替换它们。

    【讨论】:

    • 谢谢,但是我怎样才能从控制器返回图像的二进制内容?
    • 谢谢解决!我将继续对静态资源使用播放,因为现在客户只要求一次静态内容(在第一次请求时)
    • 无论如何我还是推荐外部服务器,检查我的帖子脚本:)
    • 是的,这是最好的解决方案,但无论如何我想提供一种简单的方法来在一台服务器上运行我的开源 projetc。你知道asset/ coffe 和less 资源是否仍然在不调用Asset 类的情况下编译?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-04
    • 2010-10-26
    • 1970-01-01
    • 2010-10-26
    • 2013-03-20
    • 2013-07-16
    • 1970-01-01
    相关资源
    最近更新 更多