这个filter 中报Only one connection receive subscriber allowed.
主要是body体为null的情况
@Component
public class DecryptionFilter implements GlobalFilter, Ordered {
@SneakyThrows
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
解决办法:
参考:https://blog.csdn.net/weixin_37644979/article/details/115264027
完全代码:
package com.riocento.filter;
import com.alibaba.fastjson.JSONObject;
import io.netty.buffer.ByteBufAllocator;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.CoreSubscriber;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Iterator;
/**
* 解密过滤器
* 对请求的request进行解密
*/
@Slf4j
@Component
public class DecryptionFilter implements GlobalFilter, Ordered {
@SneakyThrows
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("request解密处理");
//源request对象
ServerHttpRequest request = exchange.getRequest();
//获取请求方式
HttpMethod method = request.getMethod();
URI uri = request.getURI();
log.info("请求方式:"+method);
log.info("请求地址:"+uri);
MultiValueMap queryParams = request.getQueryParams();
log.info("所有参数:"+queryParams);
//是否为加密参数
Boolean isEncrypt = false;
// GET请求解密
if(HttpMethod.GET == method){
if(queryParams.containsKey("isEncrypt")){
isEncrypt = Boolean.valueOf(queryParams.get("isEncrypt").get(0));
}
if(isEncrypt){
//加密参数
String enParams = queryParams.get("enParams").get(0);
//将参数解密
String paramsStr = AESUtil.decrypt(enParams);
//格式化参数
String urlParams = formatUrlParams(paramsStr);
//重新创建request
URI plaintUrl = new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), urlParams, uri.getFragment());
ServerHttpRequest newRequest = request.mutate().uri(plaintUrl).build();
return chain.filter(exchange.mutate().request(newRequest).build());
}
}
//POST和PUT请求解密
else if(HttpMethod.POST == method
|| HttpMethod.PUT == method) {
if(queryParams.containsKey("isEncrypt")){
isEncrypt = Boolean.valueOf(queryParams.get("isEncrypt").get(0));
}
if(isEncrypt){
URI plaintUrl = null;
//处理url参数
if(queryParams.size() > 0 && queryParams.containsKey("enParams")){
//加密参数
String urlEnParams = queryParams.get("enParams").get(0);
//将参数解密
String urlParamsStr = AESUtil.decrypt(urlEnParams);
//格式化参数
String urlParams = formatUrlParams(urlParamsStr);
//重新创建uri
plaintUrl = new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), urlParams, uri.getFragment());
}else{
plaintUrl = uri;
}
//处理表单参数
//获取表单信息
Flux dataBufferFlux = request.getBody();
//获取body中的数据
String strBody = FilterRequestResponseUtil.resolveBodyFromRequest(dataBufferFlux);
//获取加密参数
String enParams = getEnParams(strBody);
//将参数解密
String paramsStr = AESUtil.decrypt(enParams);
ServerHttpRequest newRequest = request.mutate().uri(plaintUrl).build();
DataBuffer bodyDataBuffer = stringBuffer(paramsStr);
if(paramsStr == null) {
newRequest = new ServerHttpRequestDecorator(newRequest) {
@Override
public Flux getBody() {
return Flux.just(bodyDataBuffer);
}
};
// 构建新的请求头
HttpHeaders headers = new HttpHeaders();
headers.putAll(exchange.getRequest().getHeaders());
// 重新设置CONTENT_LENGTH
int length = 0;
headers.remove(HttpHeaders.CONTENT_LENGTH);
headers.setContentLength(length);
newRequest = new ServerHttpRequestDecorator(newRequest) {
@Override
public HttpHeaders getHeaders() {
return headers;
}
};
return chain.filter(exchange.mutate().request(newRequest).build());
}
Flux bodyFlux = Flux.just(bodyDataBuffer);
newRequest = new ServerHttpRequestDecorator(newRequest) {
@Override
public Flux getBody() {
return bodyFlux;
}
};
// 构建新的请求头
HttpHeaders headers = new HttpHeaders();
headers.putAll(exchange.getRequest().getHeaders());
// 重新设置CONTENT_LENGTH
int length = paramsStr.getBytes().length;
headers.remove(HttpHeaders.CONTENT_LENGTH);
headers.setContentLength(length);
newRequest = new ServerHttpRequestDecorator(newRequest) {
@Override
public HttpHeaders getHeaders() {
return headers;
}
};
return chain.filter(exchange.mutate().request(newRequest).build());
}
}
//DELETE等请求方式不做处理
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
/**
* 格式化url参数
* @param paramsStr 字符串参数
*/
private String formatUrlParams(String paramsStr){
StringBuilder stbResult = new StringBuilder();
if(Strings.isNotEmpty(paramsStr)){
if(paramsStr.startsWith("{")){
JSONObject paramsJSON = JSONObject.parseObject(paramsStr);
Iterator iterator = paramsJSON.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
String value = paramsJSON.getString(key);
if(stbResult.length() > 0){
stbResult.append("&");
}
stbResult.append(key).append("=").append(value);
}
}else{
stbResult.append(paramsStr);
}
}
return stbResult.toString();
}
/**
* 获取加密字符串参数
* @return
*/
private String getEnParams(String paramsStr){
String result = null;
if(Strings.isNotEmpty(paramsStr)){
if(paramsStr.startsWith("{")){
//将字符串转换为JSON格式
JSONObject jsonBody = JSONObject.parseObject(paramsStr);
result = jsonBody.getString("enParams");
}else if(paramsStr.indexOf("=") > 0){
String[] paramsArr = paramsStr.split("=");
result = paramsArr[1];
}
}
return result;
}
private DataBuffer stringBuffer(String value) {
if(value == null) {
NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(0);
return buffer;
}
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
buffer.write(bytes);
return buffer;
}
}