I have a backend written in Java (SpringBoot) which sends the response to the frontend. I am working with too many data in json, so I decided to compress it using GZIP for a quicker transaction, but I have found several errors in the code, due to I don't know very well how to deal with some classes.
I use the postHandle() method with the code above (which I found in stackoverflow in other question):
#Override
public void postHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
ByteArrayOutputStream obj=new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(obj);
gzip.write(request.getBytes("UTF-8"));
gzip.close();
}
The problem is that my request has not a getBytes() method, so it couldn't be done.
Any idea of how I can do it? I need to compress every data is send from backend to frontend.
Thank you in advance!
Related
In spring I have a controller with an endpoint like so:
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
#ResponseBody
public OutputStuff createStuff(#RequestBody Stuff stuff) {
//my logic here
}
This way if doing a POST on this endpoint, the JSON in request body will be automatically deserialized to my model (Stuff). The problem is, I just got a requirement to log the raw JSON as it is coming in! I tried different approaches.
Inject HttpServletRequest into createStuff, read the body there and log:
Code:
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
#ResponseBody
public OutputStuff createStuff(#RequestBody Stuff stuff, HttpServletRequest req) {
StringBuilder sb = new StringBuilder();
req.getReader().getLines().forEach(line -> {
sb.append(line);
});
//log sb.toString();
//my logic here
}
The problem with this is that by the time I execute this, the reader's InputStream would have already been executed to deserialize JSON into Stuff. So I will get an error because I can't read the same input stream twice.
Use custom HandlerInterceptorAdapter that would log raw JSON before the actual handler is called.
Code (part of it):
public class RawRequestLoggerInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
StringBuilder sb = new StringBuilder();
req.getReader().getLines().forEach(line -> {
sb.append(line);
});
//log sb.toString();
return true;
}
}
The problem with this tho is, that by the time the deserialization to stuff happens, the InputStream from the request would have been read already! So I would get an exception again.
Another option I considered, but not implemented yet, would be somehow forcing Spring to use my custom implementation of HttpServletRequest that would cache the input stream and allow multiple read of it. I have no idea if this is doable tho and I can't find any documentation or examples of that!
Yet another option would be not to read Stuff on my endpoint, but rather read the request body as String, log it and then deserialize it to Stuff using ObjectMapper or something like that. I do not like this idea either tho.
Are there better solutions, that I did not mention and/or am not aware of? I would appreciate help. I am using the latest release of SpringBoot.
To read the request body multiple times, we must cache the initial payload. Because once the original InputStream is consumed we can't read it again.
Firstly, Spring MVC provides the ContentCachingRequestWrapper class which stores the original content. So we can retrieve the body multiple times calling the getContentAsByteArray() method.
So in your case, you can make use of this class in a Filter:
#Component
public class CachingRequestBodyFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest currentRequest = (HttpServletRequest) servletRequest;
ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(currentRequest);
// Other details
chain.doFilter(wrappedRequest, servletResponse);
}
}
Alternatively, you can register CommonsRequestLoggingFilter in your application. This filter uses ContentCachingRequestWrapper behind the scenes and is designed for logging the requests.
As referenced in this post: How to Log HttpRequest and HttpResponse in a file?, spring provides the AbstractRequestLoggingFilter you can use to log the request.
AbstractRequestLoggingFilter API Docs, found here
I also tried to do that in Spring but i could not find way to pass my custom http request to chain so what did was,i have written traditional j2ee filter in that i have passed my custom http request to chain that is it then onward i can read http request more than once
Check this example http://www.myjavarecipes.com/how-to-read-post-request-data-twice-in-spring/
public class myServlet extends httpservlet
{
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
{
PrintWriter out = response.getWriter();
out.println(--------"HTML CODE"------);
}
}
I'm new to servlets and web programming. While practicing, I'm stuck at some general doubt. What exactly does the PrintWriter() object do in a servlet? Just directing the HTML code to output stream?
In Java, to handle I/O operations, there are different I/O classes like Reader, Writer, InputStream, OutputStream classes etc. In Servlet, when you want to do output operation i.e., writing HTML content in web page, you need one of these classes. More info on these classes, you can get from this link.
So we create PrintWriter instance from the response and invoke its write() method to write simple HTML contents.
getWriter() method of HttpServletResponse returns a PrintWriter object which can be used to send text to client side, and yes it may be used to send html code to the client side.
I want to limit the size of accepted application/json http request bodys. So that it is not possible to send multiple megabytes of json to my application, which are then processed and make my app run for a long time.
I've read here that there is no out of the box solution to do this.
Spring boot Embedded Tomcat "application/json" post request restriction to 10KB
Is there another solution beside implementing something myself.
For me this seems like a very common use-case and I can't believe that there is no general solution for this, because this is a very easily exploitable security issue.
there is no out of the box solution, but simplest way would be to write a filter to check request length, something like this
#Component
static class ApplicationJsonRequestSizeLimitFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (isApplicationJson(request) && request.getContentLengthLong() > 10000) {
throw new IOException("Request content exceeded limit of 10000 bytes");
}
filterChain.doFilter(request, response);
}
private boolean isApplicationJson(HttpServletRequest httpRequest) {
return (MediaType.APPLICATION_JSON.isCompatibleWith(MediaType
.parseMediaType(httpRequest.getHeader(HttpHeaders.CONTENT_TYPE))));
}
}
you can try this for post requests in spring boot :
server.tomcat.max-http-form-post-size
I am having trouble seeing how i can read form the stream when its being read up in the chain somewhere.
here is my function
#POST
#Consumes(["application/json"])
public Response addGift(#Context HttpServletRequest request,#QueryParam("from") int from,
#ApiParam(value = "Indiviual Gift object to be inserted", required = true) posiba.api.v1.IndividualGift gift) {
return Response.ok().entity("{\"Submit\": \"Success\"}").build();
}
I have a json data POST (payload , body) and a queryparam(for testing)
the request variable can access the params but when i try and read from the stream
stream.available() returns 0 and if i try and get anything out of the stream it closes it.
is there a way to inline override the input stream reader so whatever is up the chain does not read from it and i can use it locally.
solved it myself -- a bit of a hack way tho ----
the goal was to use swagger UI in my grails app so i have one method( as seen above) to tell swagger about the parameters and required etc...and then i made a separate function that accepts the request and does my custom handling of it
#POST
#Consumes(["application/json"])
public Response addGiftt(#Context HttpServletRequest request, InputStream requestBody){
//stuff...
}
I'm using Spring MVC, and I'm trying to experiment with the Facebook API, just for fun.
The problem I'm having currently, is that Facebook's GRAPH Api returns other status codes than 200 when it encounters an OAuthException. However, the body of the response is still a valid json object, and I would like to parse it into my object.
This way, my restTemplate will invoke the errorhandler, when the status code is anything else than HTTP.2xx, and not parse the response to my object.
Is there any way of configuring the RestTemplate so that it should parse the response body regardless of http status?
Thanks!
you could set a customer ResponseErrorHandler
restTemplate.setErrorHandler(customerErrorHandler)
you'll just need to implement the following two methods
boolean hasError(ClientHttpResponse response) throws IOException;
void handleError(ClientHttpResponse response) throws IOException;
in your case hasErrorcould always return false