In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly introduces "how to cache the HTTP request response body in SpringBoot". In the daily operation, I believe that many people have doubts about how to cache the HTTP request response body in SpringBoot. The editor consulted all kinds of materials and sorted out a simple and useful method of operation. I hope it will be helpful to answer the question of "how to cache the HTTP request response body in SpringBoot". Next, please follow the editor to study!
Purpose of caching request response body
A HTTP request, response information is fully recorded in the log. It is a common and effective method to troubleshoot and reproduce BUG.
But one feature of streaming is that it can only be read / written once and cannot be repeated. The next read and write is an empty stream, in order to achieve the reuse of the stream, it is necessary to cache the read and write data so that it can be read somewhere again.
The idea of realization
HttpServletRequestWrapper
HttpServletResponseWrapper
The above two classes, as anyone familiar with Servlet knows, are the decorative pattern implementations of Request and Response.
Through the decorator design pattern, we can make a copy of the read data and cache it when the Request reads the request body, and use it when logging. By the same token, the data of the Response response can be cached for logging, and then the response can be sent to the client.
The implementation ContentCachingRequestWrapper// provided by Spring ignores the related methods of HttpServletRequest, public class ContentCachingRequestWrapper extends HttpServletRequestWrapper {/ / wrapping Servlet, and does not limit the size of the request body public ContentCachingRequestWrapper (HttpServletRequest request) / / wrapping Servlet Limit the size of the request body public ContentCachingRequestWrapper (HttpServletRequest request, int contentCacheLimit) / / get the cached request body public byte [] getContentAsByteArray () / / this method is called when the request body exceeds the limit. Protected void handleContentOverflow (int contentCacheLimit)} is implemented empty by default.
For a class that is easy to understand, it is recommended to limit the body size of the request through contentCacheLimit. Because it caches the request body in memory by default, if the client initiates a malicious request, constructing a large request body may consume the memory of the clean server.
ContentCachingResponseWrapper// ignores the relevant method of HttpServletResponse public class ContentCachingResponseWrapper {/ / brushing the response data in the cache to the client void copyBodyToResponse () / / get the cache data byte [] getContentAsByteArray () / / get the cache data InputStream getContentInputStream () / / get the size of the cache data int getContentSize ()}
Very simply, through the packaging of ContentCachingResponseWrapper, any response data to the client will be cached by it, read and used repeatedly, and finally the response will be sent to the client.
Implementation of request log Controller
Very simple, the request body, add a timestamp and write back to the client.
Import java.util.HashMap;import java.util.Map;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping ("/ demo") public class DemoController {@ RequestMapping (produces = {"application/json; charset=utf-8") public Object demo (@ RequestBody (required = false) String body) {Map response = new HashMap () Response.put ("reqeustBody", body); response.put ("timesttamp", System.currentTimeMillis ()); return response;}} AccessLogFilter
Output request body / response body, time-consuming, and other information to the log through AccessLogFilter. A globally unique request-id is also generated for the current request body, which can be used as a condition for retrieval.
Import java.io.IOException;import java.nio.charset.StandardCharsets;import java.util.UUID;import javax.servlet.FilterChain;import javax.servlet.ServletException;import javax.servlet.annotation.WebFilter;import javax.servlet.http.HttpFilter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.core.annotation.Order;import org.springframework.http.MediaType;import org.springframework.stereotype.Component;import org.springframework.web.util.ContentCachingRequestWrapper Import org.springframework.web.util.ContentCachingResponseWrapper;import org.springframework.web.util.NestedServletException;@Component@WebFilter (filterName = "accessLogFilter", urlPatterns = "/ *") @ Order (- 9999) / / guarantee the first execution of public class AccessLogFilter extends HttpFilter {private static final Logger LOGGER = LoggerFactory.getLogger (AccessLogFilter.class); private static final long serialVersionUID =-7791168563871425753L / / the message body is too large @ SuppressWarnings ("unused") private static class PayloadTooLargeException extends RuntimeException {private static final long serialVersionUID = 3273651429076015456L; private final int maxBodySize; public PayloadTooLargeException (int maxBodySize) {super (); this.maxBodySize = maxBodySize } @ Override protected void doFilter (HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {ContentCachingRequestWrapper cachingRequestWrapper = new ContentCachingRequestWrapper (req 30) {/ / limit 30 bytes @ Override protected void handleContentOverflow (int contentCacheLimit) {throw new PayloadTooLargeException (contentCacheLimit) }}; ContentCachingResponseWrapper cachingResponseWrapper = new ContentCachingResponseWrapper (res); long start = System.currentTimeMillis () Try {/ / execute request chain super.doFilter (cachingRequestWrapper, cachingResponseWrapper, chain);} catch (NestedServletException e) {Throwable cause = e.getCause () / / the request body exceeds the limit and prompts if (cause instanceof PayloadTooLargeException) {cachingResponseWrapper.setStatus (HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE); cachingResponseWrapper.setContentType (MediaType.TEXT_PLAIN_VALUE) for the client response exception message in text form CachingResponseWrapper.setCharacterEncoding (StandardCharsets.UTF_8.displayName ()); cachingResponseWrapper.getOutputStream () .write ("request body is too large" .getBytes (StandardCharsets.UTF_8));} else {throw new RuntimeException (e) }} long end = System.currentTimeMillis (); String requestId = UUID.randomUUID () .toString (); / / generate a unique request ID cachingResponseWrapper.setHeader ("x-request-id", requestId) String requestUri = req.getRequestURI (); / / request String queryParam = req.getQueryString (); / / query parameter String method = req.getMethod (); / / request method int status = cachingResponseWrapper.getStatus () / / response status code / / request body / / converted to a string. In the case of limiting the size of the request body, String requestBody = new String (cachingRequestWrapper.getContentAsByteArray (), StandardCharsets.UTF_8) may be garbled here because the byte data is incomplete. / / response body String responseBody = new String (cachingResponseWrapper.getContentAsByteArray (), StandardCharsets.UTF_8); LOGGER.info ("{} {} ms", requestId, end-start); LOGGER.info ("{} {}", method, requestUri, queryParam, status) LOGGER.info ("{}", requestBody); LOGGER.info ("{}", responseBody); / / this step is important to output the cached response content to the client cachingResponseWrapper.copyBodyToResponse ();}} demonstrate normal requests and logs
Com.demo.web.filter.AccessLogFilter: a53500bc-c003-414a-9add-99655295a34f 1mscom.demo.web.filter.AccessLogFilter: POST / demo site=springboot.io&name=springboot%E4%B8%AD%E6%96%87%E7%A4%BE%E5%8C%BA 200com.demo.web.filter.AccessLogFilter: {"name": "springboot"} com.demo.web.filter.AccessLogFilter: {"reqeustBody": "{\" name\ ":\" springboot\ "}" "timesttamp": 1620395056498} requests and logs whose size exceeds the limit
Com.demo.web.filter.AccessLogFilter: 99476161-1790-48cc-86b9-0641efadc1b5 1mscom.demo.web.filter.AccessLogFilter: POST / demo site=springboot.io&name=springboot%E4%B8%AD%E6%96%87%E7%A4%BE%E5%8C%BA 413com.demo.web.filter.AccessLogFilter: {"name": "springboot"} {"name": com.demo.web.filter.AccessLogFilter: request body is too large
Because the size of the request body is limited, the request body log output here can only limit the size of bytes.
At this point, the study on "how to cache the HTTP request response body in SpringBoot" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.