ラベル Tomcat の投稿を表示しています。 すべての投稿を表示
ラベル Tomcat の投稿を表示しています。 すべての投稿を表示

2013年8月7日水曜日

Googlebot のクロール時の jsessionid

とあるシステムでアクセスログを見ていたら、Googlebot が jsessionid 付の URL でアクセスしていた・・・

初回アクセス時や、Cookie 未対応の端末の場合、jsessionid を付ける設定になっている。
セキュリティー上よろしくないのだが、ガラケー対応のサイトのため、
アプリケーションサーバ Tomcat の設定で止めることができない。

ログイン必須のページとそうでないページがあり、Googlebot がログインするわけでもないので、
無視することもできるが、SEO 的によろしくない気がする。何より気持ち悪い・・・
というわけで対応することに。

ググってみると、URL Rewrite Filter なるものがあるらしい。
mod_rewrite のフィルターバージョンとのこと。
mod_rewrite にリンク等を書き換える機能があったっけと思いつつみてみると、
<%= response.encodeURL("/world.jsp?country=usa&amp;city=nyc") %>

<c:url value="/world.jsp?country=${country}&amp;city=${city}" />

のように指定した URL が正規表現で指定した値に置換されるようだ。

SAStruts や mobylet を使用しているので、c:url はほとんど使っていないが、
フレームワークの内部的には、response.encodeURL を使っているだろうと思われるので問題はなさそう。

ただ、jsessionid を付加しておいて置換で消すというのは冗長な気がする・・・
ソースを読んだわけではないので実装がどうなっているかは分からないが・・・
最初から付加しなければいいはず。

Tomcat の HttpServletResponse.encodeURL は、
HttpServletRequest.isRequestedSessionIdFromCookie を見てた気がする、ということで、
Bot の UserAgent だった場合、HttpServletRequestWrapper を作成し、
isRequestedSessionIdFromCookie で常に true を返すことに。

public class BotFilter implements Filter {
  private static class BotRequesteWrapper extends HttpServletRequestWrapper {
    public CrawlerRequestWrapper(HttpServletRequest request) {
      super(request);
    }

    @Override
    public boolean isRequestedSessionIdFromCookie() {
      return true;
    }

    @Override
    public boolean isRequestedSessionIdFromURL() {
      return false;
    }
  }


  private static final Pattern PAT_BOT =
    Pattern.compile("Googlebot|Y!J|YahooSeeker|msnbot|bingbot");


  @Override
  public void init(FilterConfig filterConfig) throws ServletException {}

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest)request);
    chain.doFilter(PAT_BOT.matcher(req.getHeader("User-Agent")).find() ? new BotRequestWrapper(req) : request, response);
  }

  @Override
  public void destroy() {}
}

Google, Yahoo, MSN, Bing 等の場合、isRequestedSessionIdFromCookie で常に true、
念のために、isRequestedSessionIdFromURL は 常に false を返す。
そして、フィルターを設定。
<filter>
  <filter-name>botFilter</filter-name>
  <filter-class>com.example.BotFilter</filter-class>
</filter>

<filter-mapping>
  <filter-name>botFilter</filter-name>
  <url-pattern>/*</url-pattern>
  <dispatcher>REQUEST</dispatcher>
  <dispatcher>FORWARD</dispatcher>
  <dispatcher>INCLUDE</dispatcher>
  <dispatcher>ERROR</dispatcher>
</filter-mapping> 
UserAgent を Bot のものにして、Cookie を削除後アクセスすると、ものの見事に
jsessionid が付加されている・・・

何故・・・と言う事で追ってみると、どうも ServletResponse 内に ServletRequest を保持しており、
 HttpServletRequestWrapper とは別物のよう・・・

仕方がないので、HttpServletResponseWrapper を作成し、直接 encodeURL を変更することに。
public class CrawlerFilter implements Filter {
  private static class BotResponseWrapper extends HttpServletResponseWrapper {
    public BotResponseWrapper(HttpServletResponse response) {
      super(response);
    }


    @Override
    public String encodeRedirectURL(String url) {
      return url;
    }

    @Override
    public String encodeURL(String url) {
      return url;
    }
  }


  private static final Pattern PAT_BOT =
    Pattern.compile("Googlebot|Y!J|YahooSeeker|msnbot|bingbot");


  @Override
  public void init(FilterConfig filterConfig) throws ServletException {}

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    throws IOException, ServletException {
    chain.doFilter(request,
      PAT_BOT.matcher(((HttpServletRequest)request).getHeader("User-Agent")).matches() ?
        new BotResponseWrapper((HttpServletResponse)response) : response);
    }

    @Override
    public void destroy() {}
}
encodeUR(), encodeRedirectURL() ともに渡された URL を返すだけにする。

これで、jsessionid が付加されなくなった。

2012年4月22日日曜日

Apache + Tomcat のレスポンス

ここのところ忙しく、全然更新していなかったが、実際には色々嵌りまくりな日々・・・

その中でも最近一番大きかったのが、Apache + Tomcat の構成でレスポンスがおかしい現象が発生。
しばらく使っていると、別のリクエストのレスポンスが返ってくるようになる。
別のユーザのユーザ情報が見えたり・・・セッションがおかしくなったり・・・

Apache または、Tomcat のいずれかを再起動すると普通に戻るがしばらくするとまた発生し始める
プログラムのせいではないことを祈り調査。

接続は mod_proxy_ajpを使用して mod_proxy_balancer で分散していた。
分散していないテスト環境でも発生していたため、mod_proxy_balancer は調査から除外。
mod_proxy_ajp を mod_proxy_http に変更したところ発生しなくなった。
過去に何度も Apache + Tomcat, mod_proxy_ajp 構成をやったことはあるが初めての現象。

次に、Apache 2.4 を使っていたため、2.2 にダウングレード。
mod_proxy_ajp で接続して問題は発生しなかった。

つまり、Apache 2.4 の mod_proxy_ajp が問題だったと思われる。
Apache 2.4 は今回初めて使用したが、まだ早かったんだろうか・・・