HttpServletRequest & HttpServletResponse 中 Body 的获取

2023-05-16

为什么80%的码农都做不了架构师?>>>   hot3.png

获取 HttpServletRequest 中的请求体

    HttpServletRequest#getInputStream() 获取到请求的输入流,从该输入流中可以读取到请求体。不过这个流在被我们的代码 read 过后,之后的代码就会报错,因为流已经被我们读取过了 , 尝试使用 mark() , reset() 也是不行的,会抛出异常。可以通过将 HttpServletRequest 对象包装一层的方式来实现这个功能。

package org.hepeng.commons.http;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.io.IOUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * 
 * @author he peng
 * @date 2018/9/11
 */
public class BodyCachingHttpServletRequestWrapper extends HttpServletRequestWrapper {


    private byte[] body;
    private ServletInputStreamWrapper inputStreamWrapper;

    public BodyCachingHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        this.body = IOUtils.toByteArray(request.getInputStream());
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.body);
        this.inputStreamWrapper = new ServletInputStreamWrapper(byteArrayInputStream);
        resetInputStream();
    }

    private void resetInputStream() {
        this.inputStreamWrapper.setInputStream(new ByteArrayInputStream(this.body != null ? this.body : new byte[0]));
    }

    public byte[] getBody() {
        return body;
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        return this.inputStreamWrapper;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.inputStreamWrapper));
    }


    @Data
    @AllArgsConstructor
    private static class ServletInputStreamWrapper extends ServletInputStream {

        private InputStream inputStream;

        @Override
        public boolean isFinished() {
            return true;
        }

        @Override
        public boolean isReady() {
            return false;
        }

        @Override
        public void setReadListener(ReadListener readListener) {

        }

        @Override
        public int read() throws IOException {
            return this.inputStream.read();
        }
    }
}

 

获取 HttpServletResponse 中的响应体

    通过使用 ByteArrayOutputStream 将原 HttpSevletResponse 进行一层包装就可以实现。ByteArrayOutputStream 是将数据写入到它内部的缓冲区中,这样我们就可以获取到这个数据了。

package org.hepeng.commons.http;

import lombok.AllArgsConstructor;
import lombok.Data;

import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

/**
 * @author he peng
 * @date 2018/10/1
 */
public class BodyCachingHttpServletResponseWrapper extends HttpServletResponseWrapper {

    private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    private HttpServletResponse response;

    public BodyCachingHttpServletResponseWrapper(HttpServletResponse response) {
        super(response);
        this.response = response;
    }

    public byte[] getBody() {
        return byteArrayOutputStream.toByteArray();
    }

    @Override
    public ServletOutputStream getOutputStream() {
        return new ServletOutputStreamWrapper(this.byteArrayOutputStream , this.response);
    }

    @Override
    public PrintWriter getWriter() throws IOException {
        return new PrintWriter(new OutputStreamWriter(this.byteArrayOutputStream , this.response.getCharacterEncoding()));
    }


    @Data
    @AllArgsConstructor
    private static class ServletOutputStreamWrapper extends ServletOutputStream {

        private ByteArrayOutputStream outputStream;
        private HttpServletResponse response;

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setWriteListener(WriteListener listener) {

        }

        @Override
        public void write(int b) throws IOException {
            this.outputStream.write(b);
        }

        @Override
        public void flush() throws IOException {
            if (! this.response.isCommitted()) {
                byte[] body = this.outputStream.toByteArray();
                ServletOutputStream outputStream = this.response.getOutputStream();
                outputStream.write(body);
                outputStream.flush();
            }
        }
    }
}

flush() 函数是必须提供的 ,否则流中的数据无法响应到客户端 , ByteArrayOutputStream 没有实现 flush() 。像 SpringMVC 这类框架会去调用这个响应输出流中的 flush() 函数 ,而且有可能在出现多次调用的情况,多次调用会产生问题使得客户端得到错误的数据,比如这样的 :

{"errorCode":30001,"errorMsg":"用户未认证","token":null,"entity":null}{"errorCode":30001,"errorMsg":"用户未认证","token":null,"entity":null}  ,出现这种情况就说明 flush() 被调用了两次。所以需要在这里判断一下 HttpServletResponse#isCommitted()  。

获取请求体、相应体的包装类在 Filter 中的使用

package org.hepeng.commons.http.filter;

import com.tepin.commons.http.BodyCachingHttpServletRequestWrapper;
import com.tepin.commons.http.BodyCachingHttpServletResponseWrapper;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author he peng
 * @date 2018/10/2
 */
public class DemoFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        BodyCachingHttpServletRequestWrapper requestWrapper =
                new BodyCachingHttpServletRequestWrapper((HttpServletRequest) request);

        byte[] requestBody = requestWrapper.getBody();

        // TODO do something
        BodyCachingHttpServletResponseWrapper responseWrapper =
                new BodyCachingHttpServletResponseWrapper((HttpServletResponse) response);

        chain.doFilter(requestWrapper , responseWrapper);

        byte[] responseBody = responseWrapper.getBody();
        // TODO do something

    }

    @Override
    public void destroy() {

    }
}

 

转载于:https://my.oschina.net/j4love/blog/2222355

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

HttpServletRequest & HttpServletResponse 中 Body 的获取 的相关文章

  • 飞控学习常见典型问题集Q&A——无名创新(2022年4月15日)

    飞控学习常见典型问题集Q amp A 无名创新 xff08 2022年4月15日 xff09 1 第一次启动FS I6遥控器 xff0c 进入不了界面一直嘟嘟 xff0c 请问这是什么情况呢 xff1f 先把上面的英文翻译一下 xff0c
  • VFH & VFH+ & VFH*—— Path Planning

    版权声明 xff1a 本文为博主原创博文 xff0c 未经允许不得转载 xff0c 若要转载 xff0c 请说明出处并给出博文链接 最近在学习VFH算法 xff0c 感觉蛮神奇 xff0c 特意从维基百科扒来了资料 xff0c 供学习研究
  • Cannot find module 'body-parser'

    bug Cannot find module 39 body parser 39 原因很明显 xff0c 这个模块是没有的 xff0c 查看node modules目录下 xff0c 确实没有 解决办法 xff1a 重新安装这个模块 xff
  • AUTOSAR_DCM&DEM(UDS&OBD)

    1 术语与缩写 术语 DCM Diagnostic Communication Manager DEM Diagnostic Event Manager UDS Unified diagnostic services OBD On Boar
  • 使用SP Racing F3飞控&ROSflight软件包的无人机自主飞行系统

    搭建四旋翼系统 机架 xff1a XR215 Plus 328 分线板 xff1a XR215 Plus PDB 飞控 xff1a SP Racing F3 标准版 xff08 Acro xff09 86 电机 xff1a 银燕RS2205
  • ORB-SLAM3测试:数据集(单目/双目/imu)& ROS (D435 T265)

    ORB SLAM3环境配置 安装各种依赖库 orb slam3非常友好 xff0c 不用自己下载各种依赖库 xff0c 因为他们全部在thirdParty文件夹中 xff0c 编译orb slam3的同时会自动编译各种依赖库 Eigen3
  • Liunx下源代码安装&&make&&makefile

    Linux下安装软件的方式分为源代码安装和二进制安装 源代码安装 xff0c 即使用应用程序源代码进行编译安装二进制安装 xff0c 例如red hat发行的 rpm包 debian发行的 deb包 源代码安装 用c语言为例 include
  • 指针p,*p,&p之间的区别

    假设我们定义一个指针p 那么会经常使用到三个符号 xff1a 1 xff0c p xff1b p是一个指针变量的名字 xff0c 表示此指针变量指向的内存地址 xff0c 如果使用 p来输出的话 xff0c 它将是一个16进制数 2 xff
  • shell:重启&&关机

    文章目录 shutdownhaltpoweroffrebootinitsync shutdown 关机重启命令 shutdown h 10十分钟后关机shutdown h 0马上关机shutdown h now马上关机shutdown c取
  • 递归遍历无限极分类菜单、菜单树。(php版&&java版)

    文章目录 php版java版 php版 span class token operator lt span span class token operator span php span class token comment 定义一个数组
  • TCP Server&Client socket实现(Ubuntu16.04)

    TCP Server amp Client socket实现 xff08 Ubuntu16 04 xff09 1 测试 xff1a 2 TCP Server3 TCP Client 1 测试 xff1a 2 TCP Server span
  • A1&AlienGo--通过realsense-viewer调用相机

    使用机器狗时 xff0c 有时需要通过NX 树莓派上的系统来查看调用相机 xff0c 可以通过realsense提供的realsense viewer来查看 但是机器狗自带的视觉程序会开机自启占用相机 xff0c 所以首先需要杀掉这个进程
  • cv::imread(cv::String const&, int)’未定义的引用

    在 Makefile文件的195 行 LIBRARIES 43 61 opencv core opencv highgui opencv imgproc 后面添加 xff1a opencv imgcodecs opencv videoio修
  • HTTP认证模式:Basic & Digest

    引言 经常在工作中使用到了各种认证方式 xff0c 但从未考虑过这些认证方式所属的知识范畴 xff0c 同时也解释不清楚它们 曾用到的认证方式 xff08 看看是否您也用过 xff0c 但很难解释清楚他们 xff09 xff1a Basic
  • java通过HttpServletRequest获取post请求中的body内容

    在java web应用中 xff0c 我们如何获取post请求body中的内容 xff1f 以及需要注意的问题 通常利用request获取参数可以直接通过req getParameter name 的方式获取url上面或者ajax data
  • 最简单的 DRM 应用 & drm设备不工作

    https zhuanlan zhihu com p 341895843 https zhuanlan zhihu com p 75321245 编写最简单的 DRM 应用 主程序 xff1a int main int argc char
  • Flask-SQLAlchemy 中的 relationship & backref

    今天重看 Flask 时 xff0c 发现对backref仍然没有理解透彻 查阅文档后发现 xff0c 以前试图孤立地理解backref是问题之源 xff0c backref是与relationship配合使用的 一对多关系 db rela
  • 数据库防火墙&数据库加密与脱敏&数据泄露防护

    写在最前 xff1a 安全产品系列目录 xff1a 目录 amp 总述 数据库防火墙 解决数据库应用侧和运维侧两方面的问题 xff0c 是一款基于数据库协议分析与控制技术的数据库安全防护系统 主动防御 xff0c 实现数据库的访问行为控制
  • HttpServletResponse对象

    1 HttpServletResponse对象 1 Web服务器收到一个http请求 会针对每个请求创建一个HttpServletRequest和HttpServletResponse对象 向客户端发送数据找HttpServletRespo
  • spring mvc中post、get方法获取参数的几种方式

    get与post两种方式的区别 对于本次主题而言 最显著的区别就是get请求方式参数是在url后 而post请求方式的参数是在request body中 因此两者获取参数的方式也大不一样 Getter Setter AllArgsConst

随机推荐

  • 在sublime text3中配置并使用LaTex

    准备工作 Sublime Text3 安装并配置好Package Control xff0c 若没有安装也没关系 xff0c 我已经把常用的插件都放到了我的GitHub xff0c 可以按照说明复制到指定路径即可 MiKTeX 下载并安装
  • Python爬取网站上面的数据很简单,但是如何爬取APP上面的数据呢

    前言 在我们在爬取手机APP上面的数据的时候 xff0c 都会借助Fidder来爬取 今天就教大家如何爬取手机APP上面的数据 环境配置 1 Fidder的安装和配置 下载Fidder软件地址 xff1a https www telerik
  • linux安装redis教程yum,linux下yum安装redis以及使用

    1 yum install redis 安装redis数据库 2 service redis start Redirecting to bin systemctl start redis service 开启redis服务 方式一 开启re
  • 存储过程:数据的插入和更新

    存储过程的功能非常强大 xff0c 在某种程度上甚至可以替代业务逻辑层 xff0c 接下来就一个小例子来说明 xff0c 用存储过程插入或更新语句 1 数据库表结构 所用数据库为Sql Server2008 2 创建存储过程 xff08 1
  • win10下VS2017配置GSL库

    GSL库 xff1a GNU Scientific Library 1 下载 xff1a 下载Complete package except sources和Sources两个exe文件 2 安装 xff1a 将两个exe安装 xff0c
  • 微信开放平台开发——网页微信扫码登录(OAuth2.0)

    1 OAuth2 0 OAuth xff08 开放授权 xff09 是一个开放标准 xff0c 允许用户让第三方应用访问该用户在某一网站上存储的私密的资源 xff08 如照片 xff0c 视频 xff0c 联系人列表 xff09 xff0c
  • 安全和取证Linux发行版Kali Linux 2018.4 发布

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 公告说 xff0c 欢迎来到2018年的第四个也是最后一个版本 xff0c Kali Linux 2018 4 xff0c 可以立即下载 这个版本将我们的内核升级到4 18
  • 使用Rust + Electron开发跨平台桌面应用 ( 二 )

    前言 在上一篇文章使用Rust 43 Electron开发跨平台桌面应用 一 中 xff0c 我们将Rust 43 Electron结合起来 xff0c 使用Rust编写核心业务逻辑 xff0c 并编译成node库提供给Electron的U
  • linux高级文件系统管理——btrfs

    前几天 xff0c 关于高级文件系统方面也给大家分享过RAID和LVM xff0c 今天给大家分享的这款文件系统可能比这两者更先进 xff0c 可以将其二者合二为一 第一 xff0c 它可以使用磁盘或者分区大小不一样的设备组建RAID xf
  • 字符串 - 字符串排序

    1 字符串排序 对于许多排序应用来说 xff0c 决定顺序的键都是字符串 给定一列字符串 xff0c 需要按一定顺序排列整齐方便后序处理 2 键索引计数法 这个方法名字有点拗口 xff0c 过程有点绕 xff0c 但是每一步其实很简单 举个
  • iOS-高德地图API的定位与搜索功能

    环境 xff1a Xcode10 1 Swift4 2 真机6s xff0c ios11 Demo xff1a https github com cxymq AmapSwift 高德地图API使用 需要 xff08 https lbs am
  • iOS 录音,播放并上传

    1 界面布局 xff0c 以及相关功能 点击中间开始录音 xff0c 点击左上角播放或暂停播放 xff0c 点击右上角移除文件 2 定义相关属性 import 34 SendVoiceController h 34 import impor
  • 【Python基础】request.post()方法

    00 序言 爬取懂che帝的车型信息时 xff0c 没太整明白request post 里面的参数是干什么用的 xff0c 所以写篇学习笔记提醒一下自己 url 61 39 https www dongchedi com motor bra
  • 老虎证券web端PWA实践总结

    历时两个月 xff0c PWA功能终于在web端稳定落地使用 xff0c 网站 web itiger com 从最新研究到落地上线 xff0c 遇到不少坑 xff1b 开发过程中也参考了不少资料 xff0c 但总有那么几个是没有答案 xff
  • 硬盘inode节点简单介绍

    一 inode是什么 xff1f 理解inode xff0c 要从文件储存说起 文件储存在硬盘上 xff0c 硬盘的最小存储单位叫做 34 扇区 34 xff08 Sector xff09 每个扇区储存512字节 xff08 相当于0 5K
  • NoMachine 远程桌面控制

    它是一个基于企业级对比套装的开源的终端服务器 它允许用户在连接速度缓慢或者窄带宽的情况下 xff0c 对X11会话进行远程访问 NX项目提供一整套的运行库文件以及优化的来自X11 xff0c SMB xff0c IPP xff0c HTTP
  • Angular之路--带你来搭建Webpack 2 + Angular 4项目

    上个月Angular发布了4 0 0版本 xff0c 少年们 xff0c 赶快学起来吧 xff0c 这篇文章带领大家搭建一个简单的Angular应用 xff0c 会尽量详细的把每个点都解释到 首先我选择了用webpack2来作为打包工具 x
  • C- unsigned :1之位域分析

    1 首先回忆结构体 我们都知道定义一个结构体可以这样的方式定义 struct Point float x float y point 等价于 struct Point point 除此之外 如果不想声明结构体 只想定义结构体的话 还可以这样
  • ShareSDK自定义UI的方法

    说明 xff1a 我们的分享菜单可以修改背景 xff0c 里面的图标以及文字 xff0c 颜色等 xff0c 另外可以自己自定义UI xff0c 用自己的方法写界面 xff0c 写好了之后可以调用我们以下无UI的分享方法 xff0c 另外我
  • HttpServletRequest & HttpServletResponse 中 Body 的获取

    为什么80 的码农都做不了架构师 xff1f gt gt gt 获取 HttpServletRequest 中的请求体 HttpServletRequest getInputStream 获取到请求的输入流 xff0c 从该输入流中可以读取