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

本文探讨了为什么HttpServletRequest的输入流只能读取一次的原因,由于ServletInputStream未重写reset方法,导致不能重复读取。为解决此问题,提出了一种通过自定义HttpServletRequestWrapper实现body数据缓存的方法,以便在Springboot过滤器中多次读取request body。同时,介绍了在Springboot中设置过滤器的相关注解和配置。
摘要由CSDN通过智能技术生成

需求: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,这一点查看其源码便知:
解决HttpServletRequest的输入流只能读取一次的问题

我们再来看看ServletInputStream,可以看到该类没有重写mark()reset()以及markSupported()方法:
解决HttpServletRequest的输入流只能读取一次的问题

综上,InputStream默认不实现reset的相关方法,而Servle

网关过滤器通常用于处理HTTP请求和响应,在网关层面进行拦截、处理和转发。在使用网关过滤器获取请求体(body)参数时,需要注意请求体的类型和内容大小。通常,如果请求体是JSON格式,可以通过解析JSON来获取参数;如果请求体是表单数据,则可以按照表单的格式解析获取参数。 以Java中Spring Cloud Gateway为例,可以使用`GatewayFilter`接口实现自定义的过滤逻辑来读取和修改请求体。以下是一个简单的示例: ```java import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import reactor.core.publisher.Mono; @Component public class BodyFilter extends AbstractGatewayFilterFactory<BodyFilter.Config> { public BodyFilter() { super(Config.class); } @Override public GatewayFilter apply(Config config) { return (exchange, chain) -> { ServerHttpRequest request = exchange.getRequest(); // 检查请求体是否可读 if (request.getMethodValue().equalsIgnoreCase("POST") && request.getHeaders().getContentType().equals(MediaType.APPLICATION_JSON)) { Mono<String> modifiedBody = request.getBody() .map(data -> { // 将数据转换为字符串 String requestBody = new String(data.array()); // 解析JSON字符串并获取参数 // 示例:假设我们要获取一个名为"param"的参数 // String paramValue = ...; // 修改参数后重新设置请求体 // requestBody = requestBody.replace("旧值", "新值"); return requestBody; }) .defaultIfEmpty("") .map(body -> exchange.getRequest().mutate().body(BodyInserters.fromValue(body)).build()); // 使用修改后的请求体创建新的ServerHttpRequest ServerHttpRequest mutableReq = modifiedBody.map(body -> exchange.getRequest().mutate().body(BodyInserters.fromValue(body)).build()).block(); return chain.filter(exchange.mutate().request(mutableReq).build()); } return chain.filter(exchange); }; } public static class Config { // 配置字段 } } ``` 在这个示例中,过滤器只处理了POST请求,并且只处理了内容类型为`application/json`的请求体。如果请求体是JSON格式,它会被转换为字符串,然后可以进行进一步的解析和修改。注意,由于`ServerHttpRequest.BodyContent`是一个只读的流,所以这使用了`map`来转换和重新封装请求体。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值