1

我尝试实现一个 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 路径的请求都会写入该日志行。在 中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.

如上所述,当我调用时,日志行得到 printet 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.

但对于我们正在测试的服务器,情况并非如此。这里只有当 URI 的上下文名称对 tomcat 是“已知的”时才调用 Valve,即调用 .../some-webapp/ 将打印日志行,而调用 .../non-existing-webapp / 根本不会做任何事情 - 根本不调用阀门。
尽管如此,在这种情况下,tomcat 仍将该请求处理为发送到客户端的 404,其中包含“Apache-Coyote something”作为响应标头。

我不知道如何进一步调试它,尤其是tomcat“选择”管道或其他任何东西的过程 - 有什么想法吗?

谢谢!

4

2 回答 2

2

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

于 2014-11-19T10:19:02.500 回答
0

在版本 6 中(不确定在早期版本中会发生什么)- 8 如果 Tomcat 确定需要重定向,它不会调用 Valve,因此令人惊讶的是,只有在映射阶段确定上下文时,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 的情况下才会调用 Valve,例如,如果 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 使用错误的模式发送重定向。

于 2015-12-10T18:17:38.880 回答