如何在JavaEE中挂接HTTP请求的开始和结束



tl;博士:

如何在ServletRequestListener.requestDestroyed期间获取Servlet响应

简短版本

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

  • 请求启动时
  • 以及当请求结束时

并且能够检查请求和响应对象。

长版本

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

public class ExampleModuleForThisQuestion : IHttpModule
{
}

然后注册您的"模块">在web XML配置文件中:

web.config

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

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

  • BeginRequest事件
  • 结束请求事件

然后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几乎等价于Servlet请求侦听器

在Java中,显然相应的技术是创建和对象来实现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 %srn", 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 %srn", response.getStatus(), response.getStatusDescription());
}
}

但是我们如何得到回应呢

现在我收到了响应结束时的通知,我需要该请求的结果:

  • 我需要HTTP状态代码(例如,424(
  • 我需要HTTP状态描述(例如,失败的依赖项(
  • 我需要检查响应标头
  • 我需要修改响应标头

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

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

如何获取响应

您可以创建Filter而不是监听器。过滤器允许您围绕请求处理创建包装器。请参阅有关该主题的文档。

对于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(中声明过滤器,也可以这样做:

<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>

最新更新