weblux构造多body体
webflux 可以用于提升项目吞吐量,cpu利用率,其使用非阻塞异步io,基于reactor的非阻塞,发布订阅模式。优点可自行百度。
项目中因为需要构造多body体接口,并且接口功能开放,可以传入任何参数,传入好几个参数,类似 加上不定个数的@RequestPart 注解。针对原始springmvc项目可以使用 httpservletRequest作为接口入参,但对于webflux框架的话,就需要使用对应的serverHttpRequest作为接口入参
sping-web
@PostMapping
@ResponseBody
public DynamicResponse<Book> test(HttpServletRequest httpServletRequest) {
return DynamicResponse.of(()->bookService.updateBook(bookUpdateReq));
}
spring-webflux
@RequestMapping(value="/testBodys",method=RequestMethod.GET)
@ResponseBody
public Mono<ResponseEntity> testHttpRequest(ServerHttpRequest httpRequest){
return Mono.justOrEmpty(new ResponseEntity(HttpStatus.OK));
}
从webflux请求中获取请求数据
使用ServerHttpRequest可以解决接口不指定body体,传入多个body体的需求,但是业务层如何获取到响应的请求体body体呢?
网上有很多针对springCloud-gateway的相关问题解答,主要使用如下的方式:
String bodyString = new String("");
Flux<DataBuffer> body = exchange.getRequest().getBody();
body.subscribe(buffer -> {
byte[] bytes = new byte[buffer.readableByteCount()];
buffer.read(bytes);
DataBufferUtils.release(buffer);
try {
String bodyString = new String(bytes, "utf-8");
System.out.println(bodyString);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
});
// 主线程继续操作获取的 bodyString
bodyString ... 一系列操作
经过测试,会有几个问题,一个是 subsribe进行订阅的时候,由于webflux使用异步非阻塞,所以可能主线程已经开始往下走了,subscribe可能还没有执行,导致bodyString还没有获取到,其次,假如buffer一次消费不完的话,后面主线程获取的数据也不够。所以此处需要进行阻塞一下。
可以修改为
@RequestMapping(value="/testBodys",method=RequestMethod.GET)
@ResponseBody
public Mono<ResponseEntity> testHttpRequest(ServerHttpRequest httpRequest){
Flux<DataBuffer> body = httpRequest.getBody();
CountDownLatch downLatch = new CountDownLatch(1);
byte[] bytesAll = new byte[200000];
List<byte[]> byteList = new ArrayList<>();
body.doOnComplete(()->downLatch.countDown())
.subscribe(buffer -> {
byte[] bytes = new byte[buffer.readableByteCount()];
buffer.read(bytes);
DataBufferUtils.release(buffer);
// bytes 复制到bytesAll中
System.arraycopy(bytes, 0 , bytesAll, 0 ,bytes.length);
// bytes 增加到bytesList中
byteList.add(bytes);
try {
String bodyString = new String(bytes, "utf-8");
System.out.println(bodyString);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
});
// 使用 coutdownLatch去阻塞让subscirbe订阅完
try {
downLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
// bytesAll 复制到新bytes 替换掉多余的bytes[] 中为0的数组
int size = (int) byteList.stream().mapToInt(bytes -> bytes.length).count();
byte[] bytesResult = new byte[size];
System.arraycopy(bytesAll, 0 , bytesResult, 0 ,size);
// result为request 中的body的值
String result = new String(bytesResult);
// 同时获取的 bytesResult也可以 获取到请求对应的form-data, 以boundary分割
return Mono.justOrEmpty(new ResponseEntity(HttpStatus.OK));
}
其中使用 countdown进行阻塞,最后获取到请求的对应多有 byte[] ,该byte[] 无论是构造请求body,还是做别的操作,都可以,byte[]使用boundary进行分割, 可以看到多body的请求格式。