java - 如何在 JavaEE 中 Hook HTTP 请求的开始和结束?

标签 java servlets page-lifecycle java-ee-8

tl;博士:

我如何获得 ServletResponseServletRequestListener.requestDestroyed期间?

精简版

在 JavaEE 中,我想知道什么时候:

  • 请求开始时
  • 以及请求结束时

并能够检查 requestresponse对象。

长版

在 ASP.NET 世界中,如果您想知道请求何时开始和结束,您可以编写一个 IHttpModule:

public class ExampleModuleForThisQuestion : IHttpModule
{
}

然后在 Web XML 配置文件中注册您的“模块”:

web.config:

    <system.webServer>
        <modules>
            <add name="DoesntMatter" type="ExampleModuleForThisQuestion "/>
        </modules>
    </system.webServer>

在您的模块中,您可以为以下对象注册回调处理程序:

  • BeginRequest 事件
  • EndRequest 事件

Web 服务器基础结构随后调用您的 Init 方法。这是您注册希望在请求开始和请求结束时接收通知的机会:

public class ExampleModuleForThisQuestion : IHttpModule
{
   public void Init(HttpApplication application)
   {
      application.BeginRequest += new EventHandler(beginRequest); //register the "BeginRequet" event
      application.EndRequest += new EventHandler(endRequest); //register the "EndRequest" event
   }
}

现在我们在请求开始时有回调:

private void beginRequest(object sender, EventArgs e)
{
   HttpApplication application = (HttpApplication)sender;

   //Record the time the request started
   application.Context.Items["RequestStartTime"] = DateTime.Now;

   //We can even access the Request and Response objects
   application.ContenxtLog(application.Context.Request.Headers["User-Agent"]);
}

请求结束时我们有回调:

private void endRequest(object sender, EventArgs e)
{
   HttpApplication application = (HttpApplication)sender;

   //We can even access the Request and Response objects

   //Get the response status code (e.g. 418 I'm a teapot)
   int statusCode = application.Context.Response.StatusCode;

   //Get the request method (e.g. GET, POST, BREW)
   String method = application.context.Request.RequestType;

   //Get the path from the request (e.g. /ViewCustomer)
   String path = application.context.Request.AppRelativeCurrentExecutionFilePath'

   //Get when the request started - that we recorded during "Begin Request"
   DateTime requestStartTime = (DateTime)application.Context.Items["RequestStartTime"];

   //And we can modify the response
   if ((DateTime.Now - requestStartTime).TotalSeconds = 17)
       application.Context.Response.StatusCode = 451;
}

Java 几乎等价的是 ServletRequestListener

在 Java 中,apparently相应的技术是创建和实现 ServletRequestListener 的对象 界面:

@WebListener
public class ExampleListenerForThisQuestion
      implements javax.servlet.ServletRequestListener {

}

并将我们的监听器注册到应用程序服务器,方法是将其包含在我们的 web XML 配置文件中:

web.xml

<listener>
    <listener-class>ExampleListenerForThisQuestion</listener-class>
</listener>

现在我们可以实现 requestInitializedrequestDestroyed获取请求开始和结束时间的方法:

public class ExampleListenerForThisQuestion
      implements javax.servlet.ServletRequestListener {

   @Override
   public void requestInitialized(ServletRequestEvent sre) {
      ServletRequest sr = sre.getServletRequest();
      sr.setAttribute("requestStartTicks", getCurrentTickCount());

      HttpServletRequest request = (HttpServletRequest) sr;

      // e.g. "PUT /Customers/1234"
      System.out.printf("%s %s\r\n", request.getMethod());
   }

   @Override
   public void requestDestroyed(ServletRequestEvent sre) {
      ServletRequest sr = sre.getServletRequest();
      long requestStartTicks = (long)sr.getAttribute("requestStartTicks");

      HttpServletResponse response = (HttpServletRequest)...nothing, because i don't know how...

      // e.g. "226 IM Used"
      System.out.printf("%d %s\r\n", response.getStatus(), response.getStatusDescription());
   }
}

但是我们如何得到响应呢?

既然响应结束时我会收到通知,我需要该请求的结果:

  • 我需要 HTTP 状态代码(例如,424)
  • 我需要 HTTP 状态描述(例如,Failed Dependency)
  • 我需要检查响应 header
  • 我需要修改响应头

你注意到我上面代码中的一行:

HttpServletResponse response = (HttpServletRequest)...nothing, because i don't know how...

我怎样才能得到响应

最佳答案

您可以创建一个 Filter而不是听众。 过滤器允许您围绕请求处理创建包装器。参见 the documentation on that topic .

对于 HTTP,您可以使用 HTTPFilter .这可能类似于以下内容:

@WebFilter("/*")//or via deployment descriptor
public class YourFilter extends HttpFilter{ //or just Filter for general (non-HTTP) processing
    @Override
    public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) {//for generic filters, use ServletRequest/ServletResponse instead
        //before request processing 
        chain.doFilter(req, res);//calls other filters and processes request
        //after request processing
        //you can use res here
    }
}

如果不调用chain.doFilter,其他过滤器和servlet将不会被执行。

如果您更喜欢在部署描述符 (web.xml) 中声明过滤器,您可以 do that as well :

<filter>
  <filter-name>yourFilter</filter-name>
  <filter-class>your.FilterClass</filter-class>
</filter>
<filter-mapping>
  <filter-name>yourFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

关于java - 如何在 JavaEE 中 Hook HTTP 请求的开始和结束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73213473/

相关文章:

java - JTwain 无法在使用 servlet 的 jsp 中工作

java - 如果未收到响应,则重新发送 JMS 消息

asp.net - 页面生命周期中 session 状态、应用程序状态在哪里?

Java如何检查值是否已经AES加密;

java - 无法将元素添加到 map - 不支持的操作异常

java - 如何将此自定义 ListView ArrayAdapter 连接在一起?

c# - ASP.Net生命周期和控制状态和 View 状态

java - 如何计算Java中第n项是用户输入的系列的总和

java - ClassNotFoundException 打击 XMPPConnection

asp.net - HttpContext 为空?