webflux使用ServerHttpRequest 获取多body体内容

weblux构造多body体

webflux 可以用于提升项目吞吐量,cpu利用率,其使用非阻塞异步io,基于reactor的非阻塞,发布订阅模式。优点可自行百度。

项目中因为需要构造多body体接口,并且接口功能开放,可以传入任何参数,传入好几个参数,类似 加上不定个数的@RequestPart 注解。针对原始springmvc项目可以使用 httpservletRequest作为接口入参,但对于webflux框架的话,就需要使用对应的serverHttpRequest作为接口入参

sping-web

@PostMapping
    @ResponseBody
    public DynamicResponse test(HttpServletRequest httpServletRequest) {

        return DynamicResponse.of(()->bookService.updateBook(bookUpdateReq));
    }

spring-webflux

@RequestMapping(value="/testBodys",method=RequestMethod.GET)
	@ResponseBody
	public Mono testHttpRequest(ServerHttpRequest httpRequest){

    return Mono.justOrEmpty(new ResponseEntity(HttpStatus.OK));
}

从webflux请求中获取请求数据

使用ServerHttpRequest可以解决接口不指定body体,传入多个body体的需求,但是业务层如何获取到响应的请求体body体呢?

网上有很多针对springCloud-gateway的相关问题解答,主要使用如下的方式:

String bodyString = new String("");
Flux 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 testHttpRequest(ServerHttpRequest httpRequest){
		Flux body = httpRequest.getBody();
		CountDownLatch downLatch = new CountDownLatch(1);
		byte[] bytesAll = new byte[200000];
		List 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的请求格式。

 

你可能感兴趣的:(webflux,ServerHttpRe)