Các tập tin tĩnh

Phục vụ các tập tin tĩnh trên ổ đĩa

Thư mục của dự án:

config
public
  favicon.ico
  robots.txt
  404.html
  500.html
  img
    myimage.png
  css
    mystyle.css
  js
    myscript.js
src
build.sbt

Xitrum tự động phục vụ các tập tin tĩnh trong thư mực public. URLs đến các tập tin này:

/img/myimage.png
/css/mystyle.css
/css/mystyle.min.css

Để dẫn đến chúng thì:

<img src={publicUrl("img/myimage.png")} />

Để phục vụ các tập tin bình thường trong môi trường phát triển cũng như bản rút gọn của nó trong môi trường sản phẩm (là mystyle.css và mystyle.min.css như trên) thì:

<img src={publicUrl("css", "mystyle.css", "mystyle.min.css")} />

Để gửi các tập tin tĩnh trên ổ đĩa từ action, sử dụng hàm respondFile.

respondFile("/absolute/path")
respondFile("path/relative/to/the/current/working/directory")

Để tối ưu hóa tốc độ phục vụ các tập tin tĩnh, bạn có thể bỏ qua các tập tin không cần thiết với bộ lọc regex. Nếu request url không khớp với pathRegex, Xitrum sẽ respond lỗi 404 cho request đó.

Xem pathRegex trong config/xitrum.conf.

index.html fallback

Nếu không có route (không có action) cho URL /foo/bar (hoặc /foo/bar/), Xitrum sẽ tìm các tập tin tĩnh public/foo/bar/index.html (nằm trong thư mục public). Nếu tìm thấy tập tin, Xitrum sẽ respond nó về cho phía client.

404 và 500

404.html và 500.html trong thư mục public được sử dụng khi không có route nào phù hợp hoặc có một lỗi trong quá trình thực thi. Nếu bạn muốn tự kiểm soát lỗi thì:

import xitrum.Action
import xitrum.annotation.{Error404, Error500}

@Error404
class My404ErrorHandlerAction extends Action {
  def execute() {
    if (isAjax)
      jsRespond("alert(" + jsEscape("Not Found") + ")")
    else
      renderInlineView("Not Found")
  }
}

@Error500
class My500ErrorHandlerAction extends Action {
  def execute() {
    if (isAjax)
      jsRespond("alert(" + jsEscape("Internal Server Error") + ")")
    else
      renderInlineView("Internal Server Error")
  }
}

Response status được đặt thành 404 hoặc 500 trước khi action được thực thi, vì vậy bạn không cần phải đặt chúng một các thủ công.

Cung cấp các tập tin tài nguyên trong classpath với WebJars convention

WebJars

WebJars cung cấp rất nhiều các thư viện web mà bạn có thể sử dụng trong project.

Ví dụ, nếu bạn muốn sử dụng Underscore.js, hãy khai báo trong tập tin build.sbt của project như sau:

libraryDependencies += "org.webjars" % "underscorejs" % "1.6.0-3"

Sau đó trong tập tin giao diện .jade:

script(src={webJarsUrl("underscorejs/1.6.0", "underscore.js", "underscore-min.js")})

Xitrum sẽ tự động sử dụng underscore.js cho môi trường phát triển và underscore-min.js cho môi trường sản phẩm.

Kết quả như sau:

/webjars/underscorejs/1.6.0/underscore.js?XOKgP8_KIpqz9yUqZ1aVzw

Nếu bạn muốn sử dụng cũng một tập tin trong cả 2 môi trường:

script(src={webJarsUrl("underscorejs/1.6.0/underscore.js")})

Khi thư viện này phụ thuộc vào thư viện kia, SBT sẽ tự động tải các thư viện liên quan về. Nếu thấy SBT không tải đúng phiên bản (có thể xác nhận bằng cách chạy lệnh sbt xitrum-package rồi xem các tập tin trong thư mục target/xitrum/lib được tạo ra), bạn có thể ép SBT dùng đúng phiên bản bạn muốn bằng dependencyOverrides Ví dụ nếu bạn thấy SBT chọn thư viện jQuery phiên bản 2.x, mà bạn lại muốn dùng phiên bản 1.x để có thể hỗ trợ Internet Explorer 6, 7, hoặc 8, thì có thể khai báo như sau:

dependencyOverrides += "org.webjars" % "jquery" % "1.11.3"

Lưu resource file trong tập tin .jar với WebJars convention

Nếu bạn là nhà phát triển thư viện và muốn phục vụ tập tin myimage.png từ trong thư viện của bạn, vốn đã là một tập tin .jar trong classpath, sau đó lưu myimage.png trong tập tin .jar với WebJars convention, ví dụ:

META-INF/resources/webjars/mylib/1.0/myimage.png

Để cung cấp tập tin:

<img src={webJarsUrl("mylib/1.0/myimage.png")} />

Trong cả môi trường, đường dẫn URL sẽ là:

/webjars/mylib/1.0/myimage.png?xyz123

Respond một tập tin trong classpath

Để respond một tập tin trong một classpath element (một tập tin .jar hoặc một thư mục), kể cả khi tập tin không được lưu với WebJars convention:

respondResource("path/relative/to/the/classpath/element")

Ex:

respondResource("akka/actor/Actor.class")
respondResource("META-INF/resources/webjars/underscorejs/1.6.0/underscore.js")
respondResource("META-INF/resources/webjars/underscorejs/1.6.0/underscore-min.js")

Cache ở phía client với ETag và max-age

Xitrum tự động thêm Etag cho các tập tin tĩnh trên đĩa và classpath.

ETags sử dụng cho các tập tin nhỏ như mã MD5 của file content. Chúng sẽ được cache để sử dụng sau. Key của cache entry là (file path, modified time). Bởi vì modified time ở các server khác nhau thì khác nhau, nên mỗi web server trong một cluster (nhóm) sẽ có riêng local ETag cache.

Với các tập tin lớn, chỉ khi sửa đổi tập tin mới sử dụng Etag. Có vẻ không thực sự hoàn hảo bởi không thể đồng nhất các tập tin trên các server khác nhau vì chúng có nhiều ETag khác nhau, nhưng nó vẫn tốt hơn là không sử dụng ETag.

publicUrlwebJarsUrl tự động thêm ETag vào URL khi chúng được generate. Ví dụ:

webJarsUrl("jquery/2.1.1/jquery.min.js")
=> /webjars/jquery/2.1.1/jquery.min.js?0CHJg71ucpG0OlzB-y6-mQ

Xitrum cũng đặt max-ageExprires header thành one year. Bạn không cần lo lắng rằng trình duyệt không chọn tập tin mới nhất khi bạn sửa đổi. Bởi vì khi một tập tin trên ổ đĩa được sửa, thuộc tính modified time của tập tin đó sẽ thay đổi, do đó URL tạo ra bởi publicUrlwebJarUrl cũng thay đổi theo. ETag cache của tập tin cũng sẽ thay đổi bởi cache key thay đổi.

GZIP

Xitrum thực hiện việc nén GZIP tự động. Thuộc tính Content-Type tại header sẽ cho biết định dạng của respond là text/html hay xml/application v.v.

Xitrum luôn tự động nén GZIP với các tập tin tĩnh, nhưng định dạng responses được tùy biến, để tối ưu hóa, Xitrum chỉ thực hiện GZIP với các response lớn hơn 1KB.

Cache ở phía Server

Để hạn chế load tập tin từ đĩa, Xitrum cache các tập tin tĩnh nhỏ trong bộ nhớ với quy tắc LRU (Lần cuối sử dụng xa nhất). Xem small_static_file_size_in_kbmax_cached_small_static_files trong config/xitrum.conf.