最近很多交互要同原生的HttpServletRequestHttpServletResponse打交道。从HttpServletRequest中读取body数据封装成某种数据结构;向HttpServletResponse写入数据并响应。传统的写法非常不优雅,今天给大家介绍一种比较优雅的方式。

HttpMessageConverter

HttpMessageConverter是Spring框架提供的一个消息转换器模型,用于在 HTTP 请求和响应之间进行转换的策略接口。它可以对输入消息HttpInputMessage进行读;也可以对输出消息HttpOutputMessage进行写。

Spring MVC的消息转换都是通过这个接口的实现来完成的。HttpMessageConverter有很多实现:

通常Spring MVC中处理Form表单提交、JSONXML、字符串、甚至Protobuf都由HttpMessageConverter 的实现来完成,前端传递到后端的body参数,后端返回给前端的数据都是由这个接口完成转换的。在Spring IoC中(Spring MVC环境)还存在一个存放HttpMessageConverter的容器HttpMessageConverters:

    @Bean@ConditionalOnMissingBeanpublic HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {return new HttpMessageConverters((Collection)converters.orderedStream().collect(Collectors.toList()));}
复制代码

我们可以直接拿来使用。那么到底怎么使用呢?那首先要搞清楚HttpInputMessageHttpOutputMessage是干什么用的。

HttpInputMessage

HttpInputMessage表示一个 HTTP 输入消息,由请求头headers和一个可读的请求体body组成,通常由服务器端的 HTTP 请求句柄或客户端的 HTTP 响应句柄实现。

HttpServletRequestServletRequest的扩展接口,提供了HTTP Servlet的请求信息,也包含了请求头和请求体,所以两者是有联系的。我们只要找出两者之间的实际关系就能让HttpMessageConverter去读取并处理HttpServletRequest携带的请求信息。

ServletServerHttpRequest

说实话还真找到了:

ServletServerHttpRequest不仅仅是HttpInputMessage的实现,它还持有了一个HttpServletRequest实例属性,ServletServerHttpRequest的所有操作都是基于HttpServletRequest进行的。我们可以通过构造为其注入HttpServletRequest实例,这样HttpMessageConverter就能间接处理HttpServletRequest了。

提取请求体实战

这里聚焦的场景是在Servlet过滤器中使用HttpMessageConverter,在Spring MVC中不太建议去操作HttpServletRequest。我选择了FormHttpMessageConverter,它通常用来处理application/x-www-form-urlencoded请求。我们编写一个过滤器来拦截请求提取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);@Overridepublic 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);}}
}
复制代码

然后执行一个POST类型,Content-Typeapplication/x-www-form-urlencoded的请求:

POST /ind HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded
Content-Length: 20a=b123&c=d123&e=f123
复制代码

控制台会打印:

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

ServletServerHttpResponse

ServletServerHttpRequest就有ServletServerHttpResponse,大致原理差不多。它正好和ServletServerHttpRequest相反,如果我们需要去处理响应问题,比如想通过HttpServletResponse写个JSON响应,大概可以这么写:

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

总结

HttpMessageConverter抽象了HTTP消息转换的策略,可以帮助我们优雅地处理一些请求响应的问题。不过有一点需要注意,请求体body只能读取一次,即使它包裹在ServletServerHttpRequest中,要注意和HttpServletRequestWrapper 的区别。

如何优雅地读写HttpServletRequest和HttpServletResponse的请求体相关推荐

  1. Maven项目下HttpServletRequest 或 HttpServletResponse需引用的依赖包

    转载: http://xyly624.blog.51cto.com/842520/865630/ Maven项目下HttpServletRequest 或 HttpServletResponse需引用 ...

  2. HttpServletrequest 与HttpServletResponse总结

    转载 http://www.cnblogs.com/liuyandeng/p/5336649.html HttpServletrequest 与HttpServletResponse总结 如果说DOM ...

  3. Struts2之HttpServletRequest、HttpServletResponse,HttpSession,Parameters处理

    在正式讲解如何获取上述对象之前,需要先搞清楚一点,类似于Struts2.SpringMVC框架之所以在诸多方面用着比较方便,简化开发人员重复机械性的工作,就是因为它们把底层的Servlet操作封装起来 ...

  4. 小明滚出---响应对象HttpServletResponse和请求对象HttpServletRequest实例

    <Servlet类的Java> @WebServlet("/studentServlet") public class StudentServlet extends H ...

  5. Maven项目下HttpServletRequest 或 HttpServletResponse显示红色

    用Idea软件,Maven项目下HttpServletRequest 或 HttpServletResponse显示红色,需引用的依赖包:servlet-api.jar,官网上对应的是:JavaSer ...

  6. python用with读文件的好处_python小课堂39 - 用 with 优雅的读写文件

    python小课堂39 - 用 with 优雅的读写文件 前言 本篇来介绍一下 Python 中的关键词 with 的小技巧.但是在了解 with 之前,需要先了解一下如何使用 Python 对文件进 ...

  7. HttpServletRequest对象,请求行、请求头、请求体

    HttpServletRequest 公共接口类HttpServletRequest继承自ServletRequest.客户端浏览器发出的请求被封装成为一个HttpServletRequest对象.对 ...

  8. Servlet API 详解(HttpServlet、HttpServletRequest、HttpServletResponse)

    系列文章目录 Servlet 的运行原理_crazy_xieyi的博客-CSDN博客 如何创建一个Servlet项目(Maven)?_crazy_xieyi的博客-CSDN博客 Tomcat下载.安装 ...

  9. HttpServletRequest和HttpServletResponse简介

    http://blog.csdn.net/tong_xinglong/article/details/12972819

最新文章

  1. 你是中层管理者?嗯,一个表面看似风光,实际却很 “鸡肋” 的重要岗位
  2. sublime text3中文文件名显示为框框,怎么解决
  3. 快速消费品行业前景及进入门槛
  4. 为容器提供持久存储,这个方法试试看
  5. C/C++ pthread 线程库的封装
  6. MySQL怎么给表简明_科学网—mySQL简明入门 - 张金龙的博文
  7. 服务器项目怎么连接数据库,服务器项目连接数据库配置
  8. 巴菲特:伯克希尔没有所谓的5G核心能力 子公司会涉足相关行业
  9. 1.3、TetGen网格化过程之描述
  10. android 电视安装apk,给一切安卓智能电视安装第三方软件市场
  11. 与计算机相关的统计表格,统计信息化 Excel与SPSS应用pdf
  12. android 源码编译apk,在Android源码里编译apk
  13. 离散数学及其应用第1章笔记总结
  14. selenium之滑块操作
  15. html logo写法,教你用CSS3打造HTML5的Logo
  16. /usr/bin/ld cannot find -lGL
  17. spring security——学习笔记(day05)-实现自定义 AuthenticationProvider身份认证-手机号码认证登录
  18. 【Linux】Linux文件锁
  19. 电子书Epub文件剖析
  20. DETR3D模型源码导读 MMDetection3D构建流程

热门文章

  1. 云计算学习1——OpenStack云计算安装部署步骤图文并茂(先电2.2)
  2. class torch.optim.lr_scheduler.StepLR
  3. java jdk17 Tomcat
  4. 程序员写代码要写注释吗?写你就输了
  5. 两分钟了解数据安全平台(DSP)具备哪些安全能力
  6. Python报错ReadTimeoutError
  7. 什么是字节码?采用字节码的好处是什么?
  8. java关闭窗口按钮_java swing 使用按钮关闭窗口
  9. 家电售后服务外包维修模式,该如何管理
  10. win7 共享 win10 打印机