SpringCloudGateway读取requestBody,适用multipart/form-data和application/json

时间:2025-02-13 11:21:45

由于requestBody中的数据默认只能读取一次,如果在filter中读取后,那controller层就拿不到参数了,创建一个预处理Filter,把exchange和request都复制出来,把参数啥的放进去然后传递复制出来的exchange和request,后面执行的filter取的都是复制出来的request中的数据,controller层接收参数就不会有问题了。预处理Filter代码如下:


import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;

import ;
import ;

/**
 * 最先执行的filter
 * 后面的filter可以取到requestBody数据,也不会影响controller层数据的接收
 */
@Order(Integer.MIN_VALUE)
@Component
public class PreHandleFilter implements GlobalFilter {

	public static final String CACHE_REQUEST_BODY_OBJECT_KEY = "cachedRequestBodyObject";

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		if (().getHeaders().getContentType() == null) {
			return (exchange);
		} else {
			return (().getBody()).flatMap(dataBuffer -> {
				(dataBuffer);
				Flux<DataBuffer> cachedFlux = Flux
						.defer(() -> ((0, ())));
				ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(()) {
					@Override
					public Flux<DataBuffer> getBody() {
						return cachedFlux;
					}
				};
				().put(CACHE_REQUEST_BODY_OBJECT_KEY, cachedFlux);

				return (().request(mutatedRequest).build());
			});
		}

	}
}

后面的Filter中取requestBody用下面的方法:

/**
 * 从requestBody中取出json或者form-data数据
 */
private String getRequestBodyFormRequest(ServerHttpRequest request) {
    Flux<DataBuffer> body = ();
    StringBuilder sb = new StringBuilder();
    (buffer -> {
        byte[] bytes = new byte[()];
        (bytes);
        String bodyString = new String(bytes, StandardCharsets.UTF_8);
        (bodyString);
    });
    return ();
}

取出来的json格式数据是正常的,直接解析用就可以。

但是form-data数据是浏览器发起请求的所有数据,示例如下:

----------------------------656104841052683944615106
Content-Disposition: form-data; name="name"


----------------------------656104841052683944615106
Content-Disposition: form-data; name="addr"

jinan
----------------------------656104841052683944615106--

所以,需要解析上面的参数名和参数值。方法也写好了,直接拿去用吧:

/**
 * 解析从requestBody中获取的form-data数据,转换为json格式
 */
private String handleFormData(String str, ServerHttpRequest request) {
    String contentType = ().getContentType().toString();
	String sep = "--" + ("multipart/form-data;boundary=", "");
	String[] strs = ("\r\n");
	boolean bankRow = false;// 空行
	boolean keyRow = true;// name=xxx行
	boolean append = false;// 内容是否拼接换行符
	Map<String, String> params = new LinkedHashMap<>();// 这里保证接收顺序,所以用linkedhashmap
	String s = null, key = null;
	StringBuffer sb = new StringBuffer();
	for (int i = 1, len =  - 1; i < len; i++) {
		s = strs[i];
		if (keyRow) {
			key = ("Content-Disposition: form-data; name=", "");
			key = (1, () - 1);
			keyRow = false;
			bankRow = true;
			sb = new StringBuffer();
			append = false;
			continue;
		}
		if ((s)) {
			keyRow = true;
			if (null != key) {
				(key, ());
			}
			append = false;
			continue;
		}
		if (bankRow) {
			bankRow = false;
			append = false;
			continue;
		}
		if (append) {
			("\r\n");
		}
		(s);
		append = true;
	}
	if (null != key) {
		(key, ());
	}
	return (params);// 这里是alibaba的fastjson,需要引入依赖
}

上面方法得出的数据示例为:{"name":"","addr":"jinan"}

-----------------完!