2014년 5월 15일 목요일

servlet-mapping url-pattern "/" vs "/*"

Java Servlet 기반의 개발을 하면서 항상 명확하게 이해하지 못하고 넘어가는 부분 중에 하나가 url-pattern이 아닌가 싶습니다. 그 중에서도 "/" 과 "/*"의 차이를 이해하지 못하고 왔던 것 같아, 이번 기회에 정리해 보려고 합니다.

Servlet 3.1 Specification - Chapter 12를 읽어 보기 바랍니다.

12.2 Specification Of Mappings 에 다음과 같은 내용이 있습니다.

In the Web application deployment descriptor, the following syntax is used to define

mappings:

  • A string beginning with a ‘/’ character and ending with a ‘/*’ suffix is used for path mapping.
  • A string beginning with a ‘*.’ prefix is used as an extension mapping.
  • The empty string ("") is a special URL pattern that exactly maps to the application's context root, i.e., requests of the form http://host:port/<contextroot>/. In this case the path info is ’/’ and the servlet path and context path is empty string (““).
  • A string containing only the ’/’ character indicates the "default" servlet of the application. In this case the servlet path is the request URI minus the context path and the path info is null.
  • All other strings are used for exact matches only.

If the effective web.xml (after merging information from fragments and annotations) contains any url-patterns that are mapped to multiple servlets then the deployment must fail.

  • '/' 로 시작해서 '/*'로 끝나는 문자열을 사용할 수 있습니다.
  • '*'.prefix 형태의 확장자를 사용할 수 있습니다.
  • 빈 문자열("")은 특별한 URL 패턴인데 application의 context root에 매핑이 됩니다. 예를 들면 "http://host:port/<contextroot>/에 매핑이 되고, path info는 '/' 됩니다. 이 때 servlet path와 context path는 빈 문자열("")이 됩니다.
  • '/' 만 있는 문자열은 default servlet을 의미합니다. 이 때 servlet path는 request URI에서 context path를 제외한 문자열이 되고 path info는 null 입니다.
  • url-pattern에 의해 여러개의 servlet이 매핑이 되면 deploy가 실패해야 합니다.

또 하나 알아야 할 것은 12.3 Implicit Mappings 인데, *.jsp의 경우는 container 내에 이미 매핑이 되어있습니다. 별도로 *.jsp 매핑을 정의하면 정의한 것을 사용하고, 정의하지 않으면 container 내에 있는 것을 사용하게 됩니다.

그럼 여기서 헷갈리는 것 중에 하나가 "/"와 "/*"의 차이입니다.
"/"는 default servlet을 의미하는 것이기 때문에, url-pattern에 "/"을 사용하면, container내에 있는 default servlet을 override하게 됩니다. 다시 말해 "/"에 매핑된 servlet이 default servlet이 되는 것입니다. default servlet의 역할은 url-pattern에 매치되지 않는 주로 정적 리소스들을(js, css, html, png 등) 전송하는 것입니다.

"/*"은 모든 요청을 처리하겠다는 뜻입니다. "/*"에 매핑된 servlet은 서버의 모든 요청을 처리하게 되는데 js, css, png, html등을 servlet이 처리해 줘야 합니다. 때문에 별로 유용하지 않는 url pattern 입니다. 여기서 servlet path 는 빈문자열("")이 됩니다

보통은 정적인 자원들은 public하게 사용되는 것이기 때문에 default servlet이 처리하도록 두는 것이 좋습니다.

그런데 "/"를 사용해야 할 때가 있을 수도 있습니다. 그렇게 되면 container의 default servlet을 사용할 수 없게 되어 정적인 자원들을 전송하는 하는 기능을 직접 구현해 줘야 합니다. Spring에서는 "/"에 대한 매핑과 함께 <mvc:default-servlet-handler>라는 태그를 사용하여 정적인 자원들을 container의 default servlet을 활용할 수 있게 해줍니다. <mvc:default-servlet-handler>를 사용하면, 매치되지 않는 요청에 대해서 Spring에서 container의 default serviet으로 forwarding 해줍니다.

댓글 없음:

댓글 쓰기