Java:サーブレットに与えられたURLの解析

2019年1月16日

サーブレットを作成してTomcatに配備し、これとApacheを連携させてサービスを構成するというやり方は良くあると思うのだが、その場合にサーブレット側に与えられたURLを解析したい場合がある。

実際の問題

こんなサーブレットを作成する。

import javax.servlet.*;
import javax.servlet.http.*;

public class SomeServlet extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
    String uri = req.getRequestURI();
    System.out.println(uri);
  }
}

すると、uriの値は、サーブレットがどのように配備されているか(tomcat上のどんなコンテキストパスになっているか)によって変わってきてしまうのである。例えば、ROOT.warとして配備した場合とfoobar.warとして配備した場合とで異なってくる。

例えば、「/sample/index.html」が呼び出された場合、ROOTではこのままだが、foobarの場合のURIは「/foobar/sample/index.html」になっている。

そこで、tomcat上に配備されたコンテキストパスによって、調整しなければならない。

解決方法

tomcat上のコンテキストパスは以下のように取得する。

String contextPath = req.getContextPath();

ここにはROOTの場合なら空文字列、foobarの場合なら「/foobar」が入ってくる。したがって、元々の「/sample/index.html」を取得する方法としては以下だ。

  protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
    String contextPath = req.getContextPath();
    String uri = req.getRequestURI();
    String realUri = uri.substring(contextPath.length());
  }

これでtomcat上の配備コンテキストパスがどうであろうが常に所望のURIを取得することができる。

その他apacheの後ろ側にtomcatが配備されている場合のいろいろ

ウェブ検索してみると、元のURLを取得する方法として以下があると言うのだが、単純には使えないようだ。未だにどうやって使用するのかわからない。

     HttpServletRequest reqがあるとして。。。

      String[]attr = new String[] {
          "javax.servlet.forward.request_uri",
          "javax.servlet.forward.context_path",
          "javax.servlet.forward.servlet_path",
          "javax.servlet.forward.path_info",
          "javax.servlet.forward.query_string"
      };
      Arrays.stream(attr).forEach(s-> {
        System.out.println(s+ ":" + req.getAttribute(s));
      });    

試してみると、すべてnull値になっている。

また、以下の属性もある。

      String[]heads = new String[] {
          "X-Forwarded-For",
          "X-Forwarded-Proto",
          "X-Forwarded-Port",
          "X-Forwarded-Host"
      };
      Arrays.stream(heads).forEach(s-> {
        System.out.println(s+ ":" + req.getHeader(s));
      });   

が、値がとれるのは、X-Forwarded-For、X-Forwarded-Hostのみであった。