정적 파일
============
디스크의 정적 파일 전송
------------------------------
프로젝트 디렉토리의 레이아웃:
::
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
참조하려면:
::
일반 파일을 개발환경에서 사용하고 압축된 버전의 파일을 프로덕션 환경에서 사용하려면
(위의 mystyle.css와 mystyle.min.css):
::
디스크의 정적 파일을 액션을 통해 전송하려면 ``respondFile`` 을 사용합니다.
::
respondFile("/absolute/path")
respondFile("path/relative/to/the/current/working/directory")
정적 파일의 전송 속도를 최적화 하기 위해
정규식 필터를 통해, 불필요한 파일의 존재를 체크하여 미연에 방지할 수 있습니다.
만약 요청된 URL이 pathRegex와 맞지 않으면 Xitrum은 해당 요청에 404를 응답합니다.
``config/xitrum.conf`` 의 ``pathRegex`` 를 참고하세요.
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
사용법:
::
개발환경과 프로덕션 환경 모두에서 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를 사용하지 않는 경우보다는 약간 낫다고 보여집니다.
``publicUrl`` 과 ``resourceUrl`` 은 자동으로 Etag가 추가되어 URLs이 생성됩니다:
::
webJarsUrl("jquery/2.1.1/jquery.min.js")
=> /webjars/jquery/2.1.1/jquery.min.js?0CHJg71ucpG0OlzB-y6-mQ
Xitrum은 헤더의 ``max-age`` 와 ``Expires`` 를 `1 년 `_ 으로 설정합니다.
브라우저가 최신 파일을 참조하지 못할 것을 염려하지 않아도 됩니다.
왜냐하면 디스크의 파일이 변경될 때 ``수정시간`` 이 변하게 되고
``publicUrl`` 과 ``resourceUrl`` 이 변하게 된 상태로 생성되기 때문입니다.
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_kb`` 와 ``max_cached_small_static_files`` 에서 확인할 수 있습니다.