前言
文章主旨: 将傳回資料拿出來,然後各種處理。
正文
先看該篇文章的示例接口:
紅色框框裡面就是傳回的 response 資料 。
現在我們想要的就是 在傳回給到調用方(前端、第三方等)前,我們抓出來資料,随便改一下東西。
例如: 我要把裡面的message 提示語改了。
建立一個全局過濾器:
WrapperResponseGlobalFilter.java
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Joiner;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.nio.charset.Charset;
import java.util.List;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR;
/**
* @Author JCccc
* @Description 攔截傳回資料, 修改傳回資料
* @Date 2021/8/16 19:22
*/
@Component
public class WrapperResponseGlobalFilter implements GlobalFilter, Ordered {
private static final Logger log = LoggerFactory.getLogger(WrapperResponseGlobalFilter.class);
@Override
public int getOrder() {
// -1 is response write filter, must be called before that
return -2;
}
private static Joiner joiner = Joiner.on("");
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpResponse originalResponse = exchange.getResponse();
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
ServerHttpResponseDecorator response = new ServerHttpResponseDecorator(originalResponse) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
// 擷取ContentType,判斷是否傳回JSON格式資料
String originalResponseContentType = exchange.getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);
if (StringUtils.isNotBlank(originalResponseContentType) && originalResponseContentType.contains("application/json")) {
Flux<? extends DataBuffer> fluxBody = Flux.from(body);
//(傳回資料内如果字元串過大,預設會切割)解決傳回體分段傳輸
return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
List<String> list = Lists.newArrayList();
dataBuffers.forEach(dataBuffer -> {
try {
byte[] content = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(content);
DataBufferUtils.release(dataBuffer);
list.add(new String(content, "utf-8"));
} catch (Exception e) {
log.info("加載Response位元組流異常,失敗原因:{}", Throwables.getStackTraceAsString(e));
}
});
String responseData = joiner.join(list);
System.out.println("responseData:"+responseData);
byte[] uppedContent = new String(responseData.getBytes(), Charset.forName("UTF-8")).getBytes();
originalResponse.getHeaders().setContentLength(uppedContent.length);
return bufferFactory.wrap(uppedContent);
}));
}
}
return super.writeWith(body);
}
@Override
public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
return writeWith(Flux.from(body).flatMapSequential(p -> p));
}
};
return chain.filter(exchange.mutate().response(response).build());
}
}
調用接口可以看到,response資料已經被我們拎出來了:
那麼我們簡單做個處理,
/**
* 傳回資料處理
*
* @param responseData
* @return
*/
private String responseHandle(String responseData) {
String responseResultJson = null;
try {
JSONObject jsonObject = JSONObject.parseObject(responseData);
jsonObject.put("message", "JCccc 收藏+關注");
responseResultJson = jsonObject.toJSONString();
} catch (Exception e) {
log.info("傳回資料處理轉化失敗,異常資訊={}",e.getMessage());
return responseData;
}
return responseResultJson;
}
再次請求,可以看到:
傳回資料裡面的message已經被我們修改成功了
PS:
還有類似,既然個人資訊這麼敏感,是不是類似一些接口傳回資料需要做統一的加密呢?
如需要,那麼也可以通過配置化讀取需要加密的ur清單,然後通過exchange把url拿出來做匹對,對responseData 做加密處理。
ServerHttpRequest request = exchange.getRequest();
URI url = request.getURI();
String urlPath = url.getPath();
System.out.println("目前請求url是:"+urlPath);
好了,該篇就到這。