为什么我的tomcat阀门没有被调用?

时间:2014-11-17 15:25:35

标签: tomcat tomcat-valve

我尝试实现一个Tomcat阀门(当前使用7.0.55),它应该拦截到达Tomcat服务的每个请求,无论Connector和whatnot,无论是否有一个具有匹配名称的主机或servlet上下文或其他什么。

阀门的invoke - 方法如下所示:

public class MyValve extends ValveBase {
    public void invoke(Request request, Response response) throws IOException,
            ServletException {
        LOG.trace("Valve is being invoked");
        getNext().invoke(request, response);
    }
}

在开发系统上,在本地进行测试,一切工作都是例外。对我的“localhost”tomcat上的任何URI路径的请求都会写入该日志行。在sever.xml中,阀门配置在任何Host元素之外:

<Server port="8005" shutdown="SHUTDOWN">
  ...
  <Service name="Catalina">
    ...
    <Engine defaultHost="localhost" name="Catalina">
      ...
      <Realm ... />
      <Valve className="a.b.c.MyValve" />
      ...
      <Host ...>
      </Host>
    </Engine>
  </Service>
</Server>

现在在我的系统的hosts文件中说,域test.domain.com映射到127.0.0.1,并且有一个部署的上下文名为some-webapp

如上所述,当我拨打http://localhost:8080/some-webapp/时,日志行会打印出来,这是预期的,当我拨打http://localhost:8080/non-existing-webapp/时也会打印出来,这也是预期的。
对于域(在server.xml中未配置)test.domain.com也是如此,因此http://test.domain.com/some-webapp/打印日志行以及http://test.domain.com/non-existing-webapp

但对于我们正在测试的服务器来说,情况并非如此。这里只有在对tomcat“知道”URI的上下文名称时才调用Valve,即调用... / some-webapp /会在调用... / non-existing-webapp时打印日志行/什么都不做 - 根本没有调用阀门。
仍然,tomcat处理该请求,因为在这种情况下发送到客户端的404包含“Apache-Coyote something”作为响应头。

我不知道如何进一步调试这个,特别是tomcat“选择”管道或其他什么的过程 - 有什么想法吗?

谢谢!

2 个答案:

答案 0 :(得分:1)

原来这是由Tomcat的webapps-dir中缺少ROOT目录引起的。我认为Tomcat确实会在很早的时间点严格过滤传入的请求,甚至在任何阀门都能处理并弄乱请求之前。 如果没有默认上下文(即没有ROOT-dir),则Tomcat(认为)知道对non-existing-webapp的请求不能成功,因此甚至不会调用阀门。使用默认上下文,Tomcat无法知道请求会发生什么,因此阀门有机会拦截请求。

答案 1 :(得分:0)

在版本6中(不确定在早期版本中会发生什么) - 8如果Tomcat确定需要重定向,则不会调用Valve,因此令人惊讶的是,只有在映射阶段确定了上下文时,Valves才能可靠地工作。

您可以检查动作发生的org.apache.catalina.connector.CoyoteAdapter类的源代码(并附上调试器,如果您愿意)

    // Parse and set Catalina and configuration specific
    // request parameters
    req.getRequestProcessor().setWorkerThreadName(THREAD_NAME.get());
    boolean postParseSuccess = postParseRequest(req, request, res, response);
    if (postParseSuccess) {
        //check valves if we support async
        request.setAsyncSupported(connector.getService().getContainer().getPipeline().isAsyncSupported());
        // Calling the container
        connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);

正如您所看到的,仅在postParseRequest返回true的情况下调用Valves,例如,如果Tomcat确定它应该在postParseRequest期间返回重定向,则不会发生这种情况。 确定需要重定向的代码:

    // Possible redirect
    MessageBytes redirectPathMB = request.getMappingData().redirectPath;
    if (!redirectPathMB.isNull()) {
        String redirectPath = URLEncoder.DEFAULT.encode(redirectPathMB.toString());
        String query = request.getQueryString();
        if (request.isRequestedSessionIdFromURL()) {
            // This is not optimal, but as this is not very common, it
            // shouldn't matter
            redirectPath = redirectPath + ";" +
                    SessionConfig.getSessionUriParamName(
                        request.getContext()) +
                "=" + request.getRequestedSessionId();
        }
        if (query != null) {
            // This is not optimal, but as this is not very common, it
            // shouldn't matter
            redirectPath = redirectPath + "?" + query;
        }
        response.sendRedirect(redirectPath);
        request.getContext().logAccess(request, response, 0, true);
        return false;
    }

在我的情况下,重定向已在org.apache.catalina.mapper.Mapper.internalMapWrapper(...)

中设置

如果您使用RemoteIpValve,这可能会造成麻烦,因为它会导致Tomcat使用错误的架构发送重定向。