How can I get the HTTP status code out of a ServletResponse in a ServletFilter?
First, you need to save the status code in an accessible place. The best to wrap the response with your implementation and keep it there:
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;
}
}
In order to use this wrapper, you need to add a servlet filter, were you can do your reporting:
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
}
}
How to return HTTP error code from servlet filter?
You need to cast servletResponse
to HttpServletResponse
first:
HttpServletResponse response = (HttpServletResponse) servletResponse;
Then use its sendError()
method:
response.sendError(HttpServletResponse.SC_FORBIDDEN);
SC_FORBIDDEN
stands for code 403.
By the way, you don't redirect to 403 page, you just respond with that status. If you do that, the servlet container will serve a special 403 page to the user. You can configure that page in your web.xml
:
<error-page>
<error-code>403</error-code>
<location>/error-403.htm</location>
</error-page>
This instructs the container to serve your custom page /error-403.htm
when you set 403 status.
If you want a redirect, you could use response.sendRedirect()
(it issues a 302 redirect).
How to set http status code when responding to servlet client from Filter class-method in tomcat
I've implemented a filter for authentication shortly. I've coded something similar to this:
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain)
{
HttpServletResponse response=(HttpServletResponse) resp;
boolean authenticated=false;
// perform authentication
if (authenticated)
{
chain.doFilter(req, response);
}
else
{
// don't continue the chain
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setHeader("WWW-Authenticate", "BASIC realm=\"Your realm\"");
response.setContentType("what you need");
PrintWriter writer=response.getWriter();
// don't set content length , don't close
}
}
Is it possible to write a servlet filter to take inspect HTTP response codes?
you can wrap your outgoing response using HttpServletResponseWrapper:
class GetStatusWrapper extends HttpServletResponseWrapper {
private int status;
GetStatusWrapper(HttpServletResponse response) {
super(response);
}
@Override
public void setStatus(int sc) {
super.setStatus(sc);
status = sc;
}
public int getStatus() {
return status;
}
}
then in your filter:
public class GetStatusResponseFilter implements Filter {
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain filterChain)
throws IOException, ServletException {
GetStatusWrapper wrapper;
wrapper = new GetStatusWrapper((HttpServletResponse) response);
filterChain.doFilter(request, wrapper);
System.out.println("status = " + wrapper.getStatus());
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
@Override
public void destroy() {
}
}
Servlet response filter for non 2xx http code
You need to include the DispatcherType in your @WebFilter declaration:
@WebFilter(urlPatterns={...}, dispatcherTypes={ERROR, REQUEST, ...})
public class ...
How to set response status code in Filter when controller returns ResponseEntity?
With the /string
endpoint, you're not modifying the status code. With the /entity
endpoint, you explicitly are (you're setting it to 200 by virtue of returning an ok).
Your filter implementation changes the response status code and then proceeds to run the rest of the filter chain -- and then the servlet. And we just established the servlet (your controller) is setting the response status code to something else.
So you need to change the response code after the servlet/controller has done its thing.
Your first thought might be to reimplement your filter like this:
@Component
public class TestFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(req, resp);
} finally {
HttpServletResponse response = (HttpServletResponse) resp;
response.setStatus(205);
}
}
}
But unfortunately, that won't work either! According to the documentation:
Note that postHandle is less useful with @ResponseBody and
ResponseEntity methods for which the response is written and committed
within the HandlerAdapter and before postHandle. That means it is too
late to make any changes to the response, such as adding an extra
header. For such scenarios, you can implement ResponseBodyAdvice and
either declare it as an Controller Advice bean or configure it
directly on RequestMappingHandlerAdapter.
This might have the desired effect you're looking for (note I set to "CHECKPOINT" just to demonstrate the point!):
@ControllerAdvice
public class TestResponseBodyAdvice<T> implements ResponseBodyAdvice<T> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public T beforeBodyWrite(T body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
//
// insert status code of choice here
response.setStatusCode(HttpStatus.CHECKPOINT);
return body;
}
}
Setting response code in Servlet Filter
My mistake was doing response.setStatus(403)
what needed to happen was
response.sendError(403);
return;
Related Topics
Why Does This Gridbaglayout Not Appear as Planned
How to Send Java.Util.Logging to Log4J
How to Cast an Object to an Int
JPA How to Make Composite Foreign Key Part of Composite Primary Key
Handling Datetime Values 0000-00-00 00:00:00 in Jdbc
Behaviour of Return Statement in Catch and Finally
How to Configure Log4J to Log Different Log Levels to Different Files for the Same Logger
Jpa, How to Use the Same Class (Entity) to Map Different Tables
Differencebetween Canonical Name, Simple Name and Class Name in Java Class
Setting Jvm/Jre to Use Windows Proxy Automatically
Hibernate - Foreign Keys Instead of Entities
How to Get an Enum Based on the Value of Its Field
Differencebetween Bounded Wildcard and Type Parameters
How to Stop a Thread Created by Implementing Runnable Interface