我试图报告从我的webapp返回的每个HTTP状态代码。然而,状态码似乎无法通过ServletResponse访问,或者即使我将它转换为HttpServletResponse。有没有办法在ServletFilter中访问这个值?如何从ServletFilter的ServletResponse中获取HTTP状态码?
回答
首先,您需要将状态码保存在可访问的位置。最好的包装您的实现的响应,并保持它有:
public class StatusExposingServletResponse extends HttpServletResponseWrapper {
private int httpStatus;
public StatusExposingServletResponse(HttpServletResponse response) {
super(response);
}
@Override
public void sendError(int sc) throws IOException {
httpStatus = sc;
super.sendError(sc);
}
@Override
public void sendError(int sc, String msg) throws IOException {
httpStatus = sc;
super.sendError(sc, msg);
}
@Override
public void setStatus(int sc) {
httpStatus = sc;
super.setStatus(sc);
}
public int getStatus() {
return httpStatus;
}
}
为了使用这种包装,您需要添加一个Servlet过滤器,是你可以做你的报告:
public class StatusReportingFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
StatusExposingServletResponse response = new StatusExposingServletResponse((HttpServletResponse)res);
chain.doFilter(req, response);
int status = response.getStatus();
// report
}
public void init(FilterConfig config) throws ServletException {
//empty
}
public void destroy() {
// empty
}
}
编写HttpServletResponseWrapper并覆盖所有的setStatus(),sendError()和sendRedirect()方法来记录所有内容。编写一个过滤器,用于在每个请求中为您的包装器交换响应对象。
有一两件事从上面大卫的回答缺少的是你也应该重写sendError的其它形式:
@Override
public void sendError(int sc, String msg) throws IOException {
httpStatus = sc;
super.sendError(sc, msg);
}
感谢William,我添加了它对我的样品。 – 2010-04-29 06:30:02
由于Servlet的3.0,有一个HttpServletResponse#getStatus()
。因此,如果有升级空间,请升级到Servlet 3.0(Tomcat 7,Glassfish 3,JBoss AS 6等),并且不需要封装。
chain.doFilter(request, response);
int status = ((HttpServletResponse) response).getStatus();
还需要包括用于#sendRedirect的包装,它会更好,如果你坚持使用旧的容器,然后初始化状态为“200”,而不是“0”
private int httpStatus = SC_OK;
...
@Override
public void sendRedirect(String location) throws IOException {
httpStatus = SC_MOVED_TEMPORARILY;
super.sendRedirect(location);
}
我可以看到您的过滤器映射位置可能会影响您的覆盖代码是否被触发的情况。例如,一个连续的过滤器可能不会包装你的回应,而是取而代之。除了这些情况之外,状态代码是否可以在响应中设置,而不用调用setStatus,sendError或sendRedirect变体?这就是为什么你已经将状态初始化为200? – 1in9ui5t 2012-12-04 16:50:52
给David拉比诺维茨一个替代的解决方案,它使用的实际状态代码(在它正在使用的包装器设置后它的变化的情况下)是:
public class StatusExposingServletResponse extends HttpServletResponseWrapper {
public StatusExposingServletResponse(HttpServletResponse response) {
super(response);
}
@Override
public void sendError(int sc) throws IOException {
super.sendError(sc);
}
@Override
public void sendError(int sc, String msg) throws IOException {
super.sendError(sc, msg);
}
@Override
public void setStatus(int sc) {
super.setStatus(sc);
}
public int getStatus() {
try {
ServletResponse object = super.getResponse();
// call the private method 'getResponse'
Method method1 = object.getClass().getMethod("getResponse");
Object servletResponse = method1.invoke(object, new Object[] {});
// call the parents private method 'getResponse'
Method method2 = servletResponse.getClass().getMethod("getResponse");
Object parentResponse = method2.invoke(servletResponse, new Object[] {});
// call the parents private method 'getResponse'
Method method3 = parentResponse.getClass().getMethod("getStatus");
int httpStatus = (Integer) method3.invoke(parentResponse, new Object[] {});
return httpStatus;
}
catch (Exception e) {
e.printStackTrace();
return HttpServletResponse.SC_ACCEPTED;
}
}
public String getMessage() {
try {
ServletResponse object = super.getResponse();
// call the private method 'getResponse'
Method method1 = object.getClass().getMethod("getResponse");
Object servletResponse = method1.invoke(object, new Object[] {});
// call the parents private method 'getResponse'
Method method2 = servletResponse.getClass().getMethod("getResponse");
Object parentResponse = method2.invoke(servletResponse, new Object[] {});
// call the parents private method 'getResponse'
Method method3 = parentResponse.getClass().getMethod("getReason");
String httpStatusMessage = (String) method3.invoke(parentResponse, new Object[] {});
if (httpStatusMessage == null) {
int status = getStatus();
java.lang.reflect.Field[] fields = HttpServletResponse.class.getFields();
for (java.lang.reflect.Field field : fields) {
if (status == field.getInt(servletResponse)) {
httpStatusMessage = field.getName();
httpStatusMessage = httpStatusMessage.replace("SC_", "");
if (!"OK".equals(httpStatusMessage)) {
httpStatusMessage = httpStatusMessage.toLowerCase();
httpStatusMessage = httpStatusMessage.replace("_", " ");
httpStatusMessage = capitalizeFirstLetters(httpStatusMessage);
}
break;
}
}
}
return httpStatusMessage;
}
catch (Exception e) {
e.printStackTrace();
return "";
}
}
private static String capitalizeFirstLetters(String s) {
for (int i = 0; i < s.length(); i++) {
if (i == 0) {
// Capitalize the first letter of the string.
s = String.format("%s%s", Character.toUpperCase(s.charAt(0)), s.substring(1));
}
if (!Character.isLetterOrDigit(s.charAt(i))) {
if (i + 1 < s.length()) {
s = String.format("%s%s%s", s.subSequence(0, i + 1),
Character.toUpperCase(s.charAt(i + 1)),
s.substring(i + 2));
}
}
}
return s;
}
@Override
public String toString() {
return this.getMessage() + " " + this.getStatus();
}
}
警告:大量的类层次结构的假设的使用SNE时aky反思和内省去获得私人数据价值。
除了大卫的回答,您还需要重写复位方法:
@Override
public void reset() {
super.reset();
this.httpStatus = SC_OK;
}
...以及已过时setStatus(INT,字符串)
@Override
public void setStatus(int status, String string) {
super.setStatus(status, string);
this.httpStatus = status;
}
- 1. Windows Phone - 如何获取HTTP状态码?
- 2. 获取HTTP状态代码
- 3. C++:从URL获取HTTP状态代码
- 4. 如何从JavaScript获取HTTP状态
- 5. 在jquery中获取http状态代码
- 6. 如何从Mule获取HTTP状态代码
- 7. 如何获取Angularjs中的状态码?
- 8. 通过MeteorJS获取HTTP状态代码
- 9. 获取HTTP状态代码描述
- 10. 获取有关HTTP状态代码
- 11. 获取HTTP状态404 -/hello /?
- 12. 实习生/ Leadfoot:如何获取HTTP状态代码
- 13. 使用curl_multi从多个URL获取HTTP状态码?
- 14. 从HttpWebRequest和HttpWebResponse获取Http状态代码号(200,301,404等)
- 15. 在C#中提取HTTP状态代码
- 16. 在Alamofire中获取HTTP状态行
- 17. 在Qt中获取http状态WebKit
- 18. 如何从异常中获取IIS子状态码?
- 19. 如何获取(py)curl中的HTTP状态消息?
- 20. 如何检查401的HTTP状态码?
- 21. 从jQuery中读取HTTP状态/错误代码的问题AJAX
- 22. HTTP状态代码
- 23. System.Net.WebException HTTP状态码
- 24. HTTP 1xx状态码
- 25. Response.Redirect HTTP状态码
- 26. http状态码200
- 27. 如何从Apigee中的服务标注捕获http状态代码
- 28. 如何从scrapy-splash获取200以外的状态代码
- 29. 如何从状态获取数据?
- 30. orTools如何从RoutingModel获取状态?
的情况下,直到页面结尾才有人阅读,请注意Joel的下面的注释,以便设置默认状态= 200,并覆盖sendRedirect(..) – 2012-10-19 15:56:54
这对于Servlet规范2.4中的较旧版本的Tomcat非常有用。谢谢! – user3621633 2016-03-01 20:13:46
response.sendRedirect()正在给予非法的StateExcpetion。我已经重写了sendRedirect也作为Joel的注释 – 2016-04-11 08:47:08