返回顶部
首页 > 资讯 > 后端开发 > Python >Springboot如何设置过滤器及重复读取request里的body
  • 775
分享到

Springboot如何设置过滤器及重复读取request里的body

2024-04-02 19:04:59 775人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录httpservletRequest的输入流只能读取一次的原因重复读取body中数据的方法SpringBoot的过滤器上面的getBody的代码需求: request的conte

需求:

request的content-type为applciation/JSON,进入controller之前需要把body中的参数取出来做一次处理,然后和hearder中的另一个参数做对比。

思路:

加一个过滤器,在过滤器中取出参数做处理,然后比较

注意:

body里的数据用流来读取,只能读取一次

HttpServletRequest的输入流只能读取一次的原因

我们先来看看为什么HttpServletRequest的输入流只能读一次,当我们调用getInputStream()方法获取输入流时得到的是一个InputStream对象,而实际类型是ServletInputStream,它继承于InputStream。

InputStream的read()方法内部有一个postion,标志当前流被读取到的位置,每读取一次,该标志就会移动一次,如果读到最后,read()会返回-1,表示已经读取完了。如果想要重新读取则需要调用reset()方法,position就会移动到上次调用mark的位置,mark默认是0,所以就能从头再读了。调用reset()方法的前提是已经重写了reset()方法,当然能否reset也是有条件的,它取决于markSupported()方法是否返回true。

InputStream默认不实现reset(),并且markSupported()默认也是返回false,这一点查看其源码便知:

我们再来看看ServletInputStream,可以看到该类没有重写mark(),reset()以及markSupported()方法:

综上,InputStream默认不实现reset的相关方法,而ServletInputStream也没有重写reset的相关方法,这样就无法重复读取流,这就是我们从request对象中获取的输入流就只能读取一次的原因。

重复读取body中数据的方法

这个自定义的requestWrapper继承了HttpServletRequestWrapper ,HttpServletRequestWrapper 是一个ServletRequest的包装类同时也是ServletRequest的实现类。

在这个自定义的requestWrapper里,用一个String做缓存,在构造方法里先把request的body中的数据缓存起来,然后重写了getInputStream,返回这个缓存的body,而不是从流中读取。

这样,在需要多次读取body的地方,只需要在过滤器中把原来的request换成这个自定义的request,然后把这个自定义的带缓存功能的request传到后续的过滤器链中。

public class BodyReaderRequestWrapper extends HttpServletRequestWrapper {
    private final String body;
 
    
    public BodyReaderRequestWrapper(HttpServletRequest request) throws IOException{
        super(request);
        StringBuilder sb = new StringBuilder();
        InputStream ins = request.getInputStream();
        BufferedReader isr = null;
        try{
            if(ins != null){
                isr = new BufferedReader(new InputStreamReader(ins));
                char[] charBuffer = new char[128];
                int readCount = 0;
                while((readCount = isr.read(charBuffer)) != -1){
                    sb.append(charBuffer,0,readCount);
                }
            }else{
                sb.append("");
            }
        }catch (IOException e){
            throw e;
        }finally {
            if(isr != null) {
                isr.close();
            }
        }
 
        sb.toString();
        body = sb.toString();
    }
 
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }
 
    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayIns = new ByteArrayInputStream(body.getBytes());
        ServletInputStream servletIns = new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }
 
            @Override
            public boolean isReady() {
                return false;
            }
 
            @Override
            public void setReadListener(ReadListener readListener) {
 
            }
 
            @Override
            public int read() throws IOException {
                return byteArrayIns.read();
            }
        };
        return  servletIns;
    }
}

springboot的过滤器

2个注解:

  • @WEBFilter(过滤器上)
  • @ServletComponentScan (加在启动类上,支持servlet components扫描(为了webfilter))
@Order(999) // 序号越低,优先级越高
// 加上WebFilter即可成为过滤器
@WebFilter(filterName="myFilter", urlPatterns="/api/workorder/service/selfAppeal")
public class ExternalFilter implements Filter  {
 
    private final static Logger logger = LoggerFactory.getLogger(ExternalFilter.class);    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        logger.info("filter init");
    }
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        ResponseObject object = new ResponseObject();
        HttpServletRequest req = (HttpServletRequest)servletRequest;
        HttpServletResponse res = (HttpServletResponse)servletResponse;
        // 一个request的包装类,初始化时缓存了body,重写了getInputStream返回缓存的body,实现重复读取body
        BodyReaderRequestWrapper requestWrapper  = new BodyReaderRequestWrapper(req);
        String requestURI = requestWrapper.getRequestURI();
        System.out.println("--------------------->过滤器:请求地址" + requestURI);
        String md5 = requestWrapper.getHeader("md5")  ;
       
        if (md5 == null || !md5.toLowerCase().equals(MD5.md5(ReqGetBody.getBody(requestWrapper)).toLowerCase())) {
            object.setStatus(501);
            object.setStatusText("数据md5校验失败");
            render(object, res);
            return;
        }
        // 这里传递下去的就是自定义的request了,所以后续的Controller才能重复读取到body里的参数
        filterChain.doFilter(requestWrapper, res);
    }
 
    @Override
    public void destroy() { 
    }
 
     
    private void render(ResponseObject object, HttpServletResponse response) {
        response.setContentType("application/json;charset=UTF-8");
        try {
            response.setStatus(200);
            response.getWriter().write(JSONObject.toJSON(object).toString());
        } catch (IOException e) {
            logger.error("ExternalFilter写入response异常");
        }
    }
}

上面的getBody的代码

从body中取值的具体操作

public class ReqGetBody {
    static public String getBody(HttpServletRequest request) {
        try {
            ServletInputStream in = request.getInputStream();
            String body;
            body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
            
            return body;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

--结束END--

本文标题: Springboot如何设置过滤器及重复读取request里的body

本文链接: https://lsjlt.com/news/142530.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Springboot如何设置过滤器及重复读取request里的body
    目录HttpServletRequest的输入流只能读取一次的原因重复读取body中数据的方法springboot的过滤器上面的getBody的代码需求: request的conte...
    99+
    2024-04-02
  • SpringBoot v2.2以上重复读取Request Body内容的解决方案
    目录SpringBootv2.2以上重复读取RequestBody内容一、需求二、解决方案三、遇到问题四、问题排查解决方案SpringBoot读取Request参数的坑后端拿参数相关...
    99+
    2024-04-02
  • SpringBoot如何配置获取request中body的json格式参数
    目录背景获取请求中的参数(非json格式参数)获取方法结论获取POST请求json格式的参数经过检索推荐方法(参看后边完整方法)实现方法使用背景 最近开发项目,因为有第三方调用我们的...
    99+
    2024-04-02
  • 如何构建可重复读取inputStream的request
    目录构建可重复读取inputStream的requestrequest中inputStream多次读取原因解决方法(缓存读取到的数据)代码构建可重复读取inputStream的req...
    99+
    2024-04-02
  • SpringBoot过滤器如何获取POST请求的JSON参数
    目录SpringBoot过滤器获取POST请求的JSON参数想到了使用过滤器来实现这个功能所以我们可以通过获取到输入流来获取body从源码我们可以看到我们创建一个类并继承这个包装类有...
    99+
    2024-04-02
  • SpringBoot基于过滤器和内存如何实现重复请求拦截功能
    这篇文章主要介绍了SpringBoot基于过滤器和内存如何实现重复请求拦截功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringBoot基于过滤器和内存如何实现重复请求拦截功能文章都会有所收获,下面我们...
    99+
    2023-07-05
  • 阿里云服务器开通密码的重要性及如何设置
    本文将探讨阿里云服务器开通密码的重要性,并介绍如何设置和保护好该密码,以确保服务器的安全性和可靠性。在使用阿里云服务器时,开通密码是至关重要的一步。它是用于访问和管理服务器的凭证,只有拥有正确密码的人才能够对服务器进行操作。因此,保护好开...
    99+
    2024-01-20
    阿里 性及 如何设置
  • 如何通过优化预读文件设置来对Win7和Vista以及XP系统的开关机提速
    今天就跟大家聊聊有关如何通过优化预读文件设置来对Win7和Vista以及XP系统的开关机提速,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。如何通过优化预读文件设置,来对Win7/Vi...
    99+
    2023-06-14
  • 阿里云服务器登录账号是至关重要的如何设置和管理你的账号
    阿里云服务器是一个强大的云计算平台,提供了大量的服务器资源和各种服务。登录阿里云服务器是使用这些资源和服务的基础,因此,一个有效的阿里云服务器登录账号是至关重要的。本文将详细介绍如何设置和管理你的阿里云服务器登录账号。 阿里云服务器登录账号...
    99+
    2023-12-15
    账号 阿里 至关重要
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作