3

Recently, many interactions have to deal HttpServletRequest and HttpServletResponse Read body data from HttpServletRequest and encapsulate it into a certain data structure; HttpServletResponse and respond. The traditional way of writing is very inelegant. Today I will introduce you to a more elegant way.

HttpMessageConverter

HttpMessageConverter is a message converter model provided by the Spring framework, which is a strategy interface for converting between HTTP requests and responses. It can read the input message HttpInputMessage ; it can also write HttpOutputMessage

HttpMessageConverter

Spring MVC is done through the realization of this interface. There are many implementations of HttpMessageConverter

HttpMessageConverter常见实现

Typically the Spring the MVC processing Form1 form submission, the JSON , the XML , string, even Protobuf by HttpMessageConverter implemented to complete, is transmitted to the rear end of the front end body parameters, return to the rear end The front-end data is converted by this interface. In the Spring the IoC in ( the Spring the MVC environment) there is a storage HttpMessageConverter container HttpMessageConverters :

    @Bean
    @ConditionalOnMissingBean
    public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
        return new HttpMessageConverters((Collection)converters.orderedStream().collect(Collectors.toList()));
    }

We can use it directly. So how do you use it? First, we must figure out HttpInputMessage and HttpOutputMessage are used for.

HttpInputMessage

HttpInputMessage represents a the HTTP input message from the request header headers and a request body readable body composition, typically by a server the HTTP request handle or a client the HTTP response handler implementation.

HttpInputMessage

And HttpServletRequest is ServletRequest expansion interface that provides the HTTP the Servlet request information, the request also includes a request header and a body, so the two are linked. As long as we find out the actual relationship between the two, HttpMessageConverter can read and process the request information carried by HttpServletRequest

ServletServerHttpRequest

To be honest, I found it:

ServletServerHttpRequest

ServletServerHttpRequest just HttpInputMessage implementation, it also holds a HttpServletRequest instance property, ServletServerHttpRequest all operations are based HttpServletRequest carried out. We can inject the HttpServletRequest instance by constructing it, so that HttpMessageConverter can indirectly process HttpServletRequest .

The actual combat of extracting the request body

The scene focused here is to use HttpMessageConverter in the Servlet filter. It is not recommended to operate HttpServletRequest in Spring MVC. I chose FormHttpMessageConverter , which is usually used to process application/x-www-form-urlencoded requests. We write a filter to intercept requests to extract body :

/**
 * 处理 application/x-www-form-urlencoded 请求
 *
 * @author  felord.cn
 */

@Component
public class FormUrlencodedFilter implements Filter {
    private final FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter();
    private static final Logger log = LoggerFactory.getLogger(FormUrlencodedFilter.class);

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException {
        String contentType = request.getContentType();
        MediaType type= StringUtils.hasText(contentType)? MediaType.valueOf(contentType):null;
        ServletServerHttpRequest serverHttpRequest = new ServletServerHttpRequest((HttpServletRequest) request);
        
        if (formHttpMessageConverter.canRead(MultiValueMap.class,type)) {
            MultiValueMap<String, String> read = formHttpMessageConverter.read(null, serverHttpRequest);
             log.info("打印读取到的请求体:{}",read);
        }
    }
}

Then execute a POST type Content-Type is application/x-www-form-urlencoded :

POST /ind HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded
Content-Length: 20

a=b123&c=d123&e=f123

The console will print:

2021-12-30 6:43:56.409  INFO 12408 --- [nio-8080-exec-1] sfds: 打印读取到的请求体:{a=[b123], c=[d123], e=[f123]}

ServletServerHttpResponse

There ServletServerHttpRequest there ServletServerHttpResponse , roughly the principle is similar. It is just the ServletServerHttpRequest . If we need to deal with the response problem, for example, if we want to HttpServletResponse , we can probably write like this:

ServletServerHttpResponse servletServerHttpResponse = new ServletServerHttpResponse(response);
// 使用json converter
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
//  authentication 指的是需要写的对象实例
mappingJackson2HttpMessageConverter.write(authentication, MediaType.APPLICATION_JSON,servletServerHttpResponse);

Summarize

HttpMessageConverter abstracts the HTTP message conversion strategy, which can help us handle some request response issues gracefully. But one thing to note is that the request body body can only be read once, even if it is wrapped in ServletServerHttpRequest , pay attention to the difference HttpServletRequestWrapper

Follow the public account: Felordcn for more information

personal blog: https://felord.cn


码农小胖哥
3.8k 声望8k 粉丝