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

为什么我的tomcat阀没有被调用?,tomcat,tomcat-valve,Tomcat,Tomcat Valve,我尝试实现一个Tomcat阀(目前使用的是7.0.55),它应该拦截到达Tomcat服务的每个请求,不管连接器和其他什么,不管是否有具有匹配名称的主机或servlet上下文或其他什么 阀门的invoke-方法如下所示: public class MyValve extends ValveBase { public void invoke(Request request, Response response) throws IOException, ServletE

我尝试实现一个Tomcat阀(目前使用的是7.0.55),它应该拦截到达Tomcat服务的每个请求,不管连接器和其他什么,不管是否有具有匹配名称的主机或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路径的请求都会写入该日志行。在
server.xml
中,阀门在任何
主机
元件外部配置:

<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,并且部署了一个名为
somewebapp
的上下文

如上所述,当我调用
http://localhost:8080/some-webapp/
,正如预期的那样,当我调用
http://localhost:8080/non-现有webapp/
,这也是预期的。
域(未在server.xml中配置)test.domain.com也是如此,因此
http://test.domain.com/some-webapp/
打印日志行以及
http://test.domain.com/non-existing-webapp

但对于我们正在测试的服务器来说,情况并非如此。这里,只有当URI的上下文名称对tomcat来说是“已知”的时候,才会调用该阀,即对…/某个webapp/的调用会打印日志行,而对…/不存在的webapp/的调用则什么也不做-根本不会调用该阀。
尽管如此,tomcat还是会处理该请求,因为发送到客户端的404在本例中包含“apachecoyotesomething”作为响应头

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


谢谢

结果表明,这是由于Tomcat的webapps目录中缺少根目录造成的。我认为Tomcat在很早的时候就对传入的请求进行了相当严格的过滤,甚至在任何阀门能够处理和处理请求之前。
如果没有默认上下文(即没有根目录),Tomcat(认为)知道对不存在的webapp的请求不能成功,因此甚至不会调用阀门。在默认上下文中,Tomcat无法知道请求将发生什么,因此valve有机会拦截请求。

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

您可以检查执行操作的
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时才会调用阀门,例如,如果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使用错误的模式发送重定向