정적 파일

디스크의 정적 파일 전송

프로젝트 디렉토리의 레이아웃:

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

Xitrum은 public 디렉토리의 정적 파일들을 자동으로 제공합니다. URLs는 다음과 같이 사용합니다:

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

참조하려면:

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

일반 파일을 개발환경에서 사용하고 압축된 버전의 파일을 프로덕션 환경에서 사용하려면 (위의 mystyle.css와 mystyle.min.css):

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

디스크의 정적 파일을 액션을 통해 전송하려면 respondFile 을 사용합니다.

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

정적 파일의 전송 속도를 최적화 하기 위해 정규식 필터를 통해, 불필요한 파일의 존재를 체크하여 미연에 방지할 수 있습니다. 만약 요청된 URL이 pathRegex와 맞지 않으면 Xitrum은 해당 요청에 404를 응답합니다.

config/xitrum.confpathRegex 를 참고하세요.

index.html 대체

만약 /foo/bar (또는 /foo/bar/) URL의 경로(액션)가 없을 경우 Xitrum은 public/foo/bar/index.html (“public” 디렉토리) 경로의 정적 파일을 탐색합니다. 파일이 존재하면 Xitrum은 해당파일을 클라이언트로 응답합니다.

404 과 500

요청에 대해 적합한 경로가 없거나 에러가 발생한 경우에는 public 디렉토리에 있는 404.html과 500.html이 사용됩니다. 핸들러를 직접 등록하고 싶은 경우:

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")
  }
}

응답에 대한 요청은 액션이 수행되기 전에 404과 500이 세팅되므로 임의로 세팅할 필요가 없습니다.

WebJar에 의한 클래스 패스내의 리소스 파일 전송

WebJars

WebJars 는 상당량의 웹 라이브러리를 제공하고 프로젝트 내에서 정의해 사용할 수 있습니다.

예를 들어 Underscore.js 를 사용하고자 하는 경우에는 프로젝트의 build.sbt 내에 정의하면 됩니다.

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

그리고 .jade 템플릿 파일에서 사용됩니다:

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

Xitrum은 자동으로 개발환경에서 underscore.js 를 사용하고 underscore-min.js 를 프로덕션 환경에서 사용합니다.

결과는 다음과 같습니다:

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

동일한 파일을 동일 환경에서 사용하려면:

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

종속된 파일들은 자동으로 다운로드 됩니다. 버전 충돌의 문제로 원하는 버전의 라이브러리가 선택되지 않았을 경우(sbt xitrum-package 명렁어를 통해 다음에 생성되는 디렉토리의 파일들을 보고 확인할 수 있습니다. target/xitrum/lib), dependencyOverrides 에서 강제로 원하는 버전의 라이브러리를 추가할 수 있습니다. 예를 들어, jQuery 2.x 이 선택되었지만 인터넷 익스플로러 6, 7, 8에서 강제로 jQuery 1.x 사용하기를 원할 경우엔 다음과 같이 사용하면 됩니다:

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

WebJars 형식으로 리소스 파일을 .jar 내에 저장하기

만약 라이브러리를 개발하여 라이브러리에 myimage.png를 추가하고 싶다면 WebJars 의 형식으로 .jar 파일의 클래스 패스에 myimage.png를 넣을 수 있습니다:

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

사용법:

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

개발환경과 프로덕션 환경 모두에서 URL은:

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

클래스 패스내의 파일 응답

클래스 패스내의 WebJars 형식으로 저장되지 않은 파일의 응답:

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

예:

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")

ETag 과 max-age의 클라이언트 캐쉬

Xitrum은 자동으로 Etag 을 디스크 내 클래스 패스의 정적파일을 사용하기 위해 추가합니다.

ETags는 작은 파일일 경우 MD5로 캐쉬되어 나중에 사용됩니다. 캐쉬 앤트리의 키는 (파일경로, 수정시간) 입니다. 왜냐하면 파일의 변경시간은 각 서버별로 상이하기 때문에 클러스터의 각 서버는 각각 로컬 ETag 캐쉬를 가지게 됩니다.

큰 파일의 경우에는 수정된 시간만을 ETag에 사용됩니다. 완벽하지는 않지만 각기 서버는 다른 ETag 정보를 가질 것으로 예상되기 때문입니다. 물론 ETag를 사용하지 않는 경우보다는 약간 낫다고 보여집니다.

publicUrlresourceUrl 은 자동으로 Etag가 추가되어 URLs이 생성됩니다:

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

Xitrum은 헤더의 max-ageExpires1 년 으로 설정합니다. 브라우저가 최신 파일을 참조하지 못할 것을 염려하지 않아도 됩니다. 왜냐하면 디스크의 파일이 변경될 때 수정시간 이 변하게 되고 publicUrlresourceUrl 이 변하게 된 상태로 생성되기 때문입니다. ETag 캐쉬 또한 업데이트 되기 때문에 키도 변하게 됩니다.

GZIP

Xitrum은 자동으로 텍스트 형식의 응답을 gzips을 적용합니다. Content-Type 헤더를 통해 형식이 text/html, xml/application 등과 같은 텍스트 형식인지를 체크해서 결정합니다.

Xitrum은 정적 파일에 대해서는 항상 gzips을 수행하지만 동적인 텍스트 응답에 대해서는 성능 최적화를 위해 1 KB 미만의 응답에 대해서는 gzips을 수행하지 않습니다.

서버 캐쉬

디스크로부터 파일 로딩을 방지하기 위해 Xitrum은 작은 정적파일에 대해서(텍스트 뿐만 아니라) 메모리에 LRU (Least Recently Used) 알고리즘을 사용합니다.

config/xitrum.conf 내의 small_static_file_size_in_kbmax_cached_small_static_files 에서 확인할 수 있습니다.