I create an function to create a session expiry date, like below:
#Override
public Long sessionTime() throws ErrorException{
Long expirySession = System.currentTimeMillis() + expirationTime;
return expirySession;
}
she is launch after every request and save this time in database,
but i must to send this time in all headers from my request in controller,
can somebody tell me how can i do this?
You can use the Response entity headers
#GetMapping("/response-entity")
public ResponseEntity<String> usingResponseEntityBuilderAndHttpHeaders() {
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("sessionTime" ,sessionTime());
return ResponseEntity.ok()
.headers(responseHeaders)
.body("ResponseEntity");
}
For more details check out https://www.baeldung.com/spring-response-header
You can do that in Filter to have a generic handler for that feature in one place.
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/filter/package-summary.html
You need to implement doFilter method in this way:
public class Example implements Filter {
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
response .addHeader("header_name", "header_value");
filterChain.doFilter(servletRequest, response);
}
}
Related
I have a #RestControllerAdvice where I handle an Exception in Spring Boot. I would like to log an information that is sent through request body. How can I get this information from a spring WebRequest?
This is my sample exception handler.
#RestControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
#Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
// I want to add something here that I could log an info that is in the request body.
return super.handleMethodArgumentNotValid(ex, headers, status, request);
}
}
#M.Deinum I tried to use ContentCachingRequestWrapper, But I could not have acess to body content. The method contentCachingRequestWrapper.getContentAsByteArray() returns null.
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
try {
ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper((HttpServletRequest) request);
wrappedRequest.getContentAsByteArray();
wrappedRequest.getInputStream();
chain.doFilter(wrappedRequest, response);
} finally {
LoggingContext.clear();
}
The comments regarding using the ContentCachingRequestWrapper are accurate, this is the implementation using your controller advice that should work.
#Component
public class MyFilter implements Filter {
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
ContentCachingRequestWrapper contentCachingRequestWrapper = new ContentCachingRequestWrapper(
(HttpServletRequest) servletRequest);
filterChain.doFilter(contentCachingRequestWrapper, servletResponse);
}
}
The advice
#RestControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
#Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
ContentCachingRequestWrapper nativeRequest = (ContentCachingRequestWrapper) ((ServletWebRequest) request).getNativeRequest();
String requestEntityAsString = new String(nativeRequest.getContentAsByteArray());
log.debug(requestEntityAsString);
return super.handleMethodArgumentNotValid(ex, headers, status, request);
}
}
RequestBody and ResponseBody can be read-only once so other ways to achieve the body in the exception handler
Visit here
I have a Spring MVC application which return ResponseEntity and clientResponse object as response body
#RestController
public class XxxController {
public void ResponseEntity(ClientRequest clientRequest) {
...
return ResponseEntity.ok(clientResponse);
}
}
But how can we get the clientResponse object or set a new Response body in Spring Boot Filter?
#Component
public class MyClassFilter implements Filter {
#Override
public void doFilter( HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
}
#Override
public void destroy() {}
#Override
public void init(FilterConfig arg0) throws ServletException {}
}
Not sure what you mean by get Response in Filter. In a filter the request is yet to be passed to controller, so there is no response yet. You can get the request though. But be careful not to read the request as in that case the request stream will be read in the filter and when it arrives at the controller the entire request stream will be already read. To set the response you can do the following:
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
response.resetBuffer();
response.setStatus(HttpStatus.OK);
response.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
response.getOutputStream().print(new ObjectMapper().writeValueAsString(myData));
response.flushBuffer(); // marks response as committed -- if we don't do this the request will go through normally!
}
you can see here why you have to flush the response. You can also do sendError HttpServletResponse#sendError How to change ContentType
If you don't flush the response, your request will continue down the filter chain (you have to add the chain.doFilter(request, response); of course!).
I am not sure with that but I think you can try this :
HttpServletResponse res = (HttpServletResponse) response;
ContentCachingResponseWrapper ccrw= new ContentCachingResponseWrapper(res);
//old body:
String content=new String(ccrw.getContentAsByteArray(), "utf-8");
//try this
HttpServletResponseWrapper hsrw=new HttpServletResponseWrapper(res);
hsrw.getOutputStream().write(/*new body*/);
//OR this
ServletResponseWrapper responseWrapper = (ServletResponseWrapper)response;
responseWrapper.getResponse().resetBuffer();
responseWrapper.getResponse().getOutputStream().write(/*new body*/);
I am having a filter. It should redirect to /b if /a is requested.
public class WebFilter extends GenericFilterBean
{
#Override
public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
String path = req.getRequestURI ().toString ();
if (path.equals ("/a") == true)
{
System.out.println ("FILTER: a -> b");
res.reset ();
res.resetBuffer();
res.sendRedirect ("b");
}
chain.doFilter (req, res);
}
}
Here is the handler for the content.
#Component
#Controller
#RequestMapping ("/")
public class WebHandler
{
#RequestMapping ("/a")
public String a ()
{
System.out.println ("a");
return "a"; // point to a.jsp
}
#RequestMapping ("/b")
public String b (HttpSession ses)
{
System.out.println ("b");
return "b"; // point to b.jsp
}
}
If I request /a in a browser, then that is the output.
FILTER: a -> b
IN a
IN b
Why is method a called?
I would expect only b because I redirect in doFilter from a to b.
How can I make that happen?
So you are actually doing a redirect although it seems you just want to direct the request to a different controller mapping.
res.sendRedirect ("b");
Just changes the response code to 302 and adds a location field, you will still hit the first controller, which is why you still see a in the logs.
The browser then acknowledges this redirect directive and will send a second request for /b.
One way to achieve what you appear to want would be to create a new Request from the submitted one, and simply override the getRequestUri() method.
#Override
public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
String path = req.getRequestURI();
if (path.equals("/a")) {
req = new HttpServletRequestWrapper((HttpServletRequest) request) {
#Override
public String getRequestURI() {
return "/b";
}
};
}
chain.doFilter (req, res);
}
This is then passed to the filter chain and everything continues as though that were the original request
I'm implementing api gateway where bases on the request uri. I need to add additional headers in chain.doFilter(request,response).
my filter is jwt filter as following
public class JwtAuthenticationFilter extends OncePerRequestFilter{
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CustomHttpServletRequest cRequest = new CustomHttpServletRequest(request);
/* authenticate user for valid token if valid then add the following header*/
if(request.getRequestURI().equals("/testService/updateHeader")) {
cRequest.putHeader("test","Test-header");
}
filterChain.doFilter(cRequest, response);
}
}
implemented based on reference:
and in my testservice and trying to fetch header in the headers i am not able to get the header name
I guess the problem is that in filterChain.doFilter(request, response) you use original request, but not new one with custom heeader. Change
filterChain.doFilter(request, response);
to
filterChain.doFilter(cRequest, response);
I have a client caching disabling filter which is mapped to all URLs.
Now I have to specifically disable the filter and allow caching when the response has anything other than html.
My current filter code is as follows:
public class NoCacheFilter implements Filter{
#Override
public void destroy() {}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("Pragma", "no-cache");
httpResponse.setHeader("Cache-Control","no-cache,no-store,max-age=0,s-maxage=0,must-revalidate,proxy-revalidate,private,max-stale=0,post-check=0");
httpResponse.setDateHeader("Expires", 0L);
filterChain.doFilter(request, response);
}
#Override
public void init(FilterConfig arg0) throws ServletException {}
}
NOTE: Just for people who want to know why I am doing this - We have some paged which generate PDF. We take this PDF File and flush to the output stream. In IE8, the flush code doesn't work and logs show that the client closed the connetion immaturely...Cannot write to committed response.... When caching is enabled, PDF get written to client normally; without any issue. A separate requirement of the existing app is to not allow caching of any page on the client.
Did you try something as simple as this:
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
filterChain.doFilter(request, response);
if(response.getContentType().indexOf("text/html")>-1){
httpResponse.setHeader("Pragma", "no-cache");
httpResponse.setHeader("Cache-Control","no-cache,no-store,max-age=0,s-maxage=0,must-revalidate,proxy-revalidate,private,max-stale=0,post-check=0");
httpResponse.setDateHeader("Expires", 0L);
}
}
It don't really disable the filter, but at least the filter don't do anything when the response is not html.
Simple, just check in the doFilter() method whether the resource is cacheable or not. You can use the request URI, content-type or MIME type for that.