Spirng cloud gateway 拦截 response修改返回内容
微服务项目中很多网关的功能真的强大,从路由,认证,鉴权到修改请求和响应内容,真正体会到spring cloud gateway 的强大;最近遇到一个返回数据需要简繁体转换的需求,没啥好说的,直接在网关统一处理;前端会传一个简繁体标识的请求头过来,判断请求头然后用工具类转换;简繁体转换的依赖<!-- 简繁体转换依赖包 --><dependency><groupId>
微服务项目中很多网关的功能真的强大,从路由,认证,鉴权到修改请求和响应内容,真正体会到spring cloud gateway 的强大;
最近遇到一个返回数据需要简繁体转换的需求,没啥好说的,直接在网关统一处理;
前端会传一个简繁体标识的请求头过来,判断请求头然后用工具类转换;
简繁体转换的依赖
<!-- 简繁体转换依赖包 -->
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>opencc4j</artifactId>
<version>1.0.2</version>
</dependency>
直接上代码
import com.dz.server.common.constants.LanguageTypeConstants;
import com.github.houbb.opencc4j.util.ZhConverterUtil;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
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.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
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;
@Slf4j
@Component
public class ResponseGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpResponse originalResponse = exchange.getResponse();
originalResponse.getHeaders().setContentType(MediaType.APPLICATION_JSON);
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) {
Flux<? extends DataBuffer> fluxBody = Flux.from(body);
return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
DataBuffer join = dataBufferFactory.join(dataBuffers);
byte[] content = new byte[join.readableByteCount()];
join.read(content);
DataBufferUtils.release(join);
// 流转为字符串
String responseData = new String(content, Charsets.UTF_8);
/** 业务逻辑,例如转换为繁体 */
String language = exchange.getRequest().getHeaders().getFirst("language");
if(StringUtils.equalsIgnoreCase(LanguageTypeConstants.zh_TW, language)){
// 转换为繁体
responseData = ZhConverterUtil.convertToTraditional(responseData);
}
byte[] uppedContent = responseData.getBytes(Charsets.UTF_8);
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());
}
@Override
public int getOrder() {
//WRITE_RESPONSE_FILTER 之前执行
return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;
}
}
其中也遇到了很多问题;例如:
1、gateway 返回数据偶尔出现的乱码的问题,经过排除是因为服务返回的数据过多,gateway 进行分段处理造成的;
可以看 gateway 返回Body 数据居然出现偶现的乱码问题, 原来是数据被截断背的锅 这篇博客;
2、还遇到更加棘手的问题:Connection has been closed BEFORE response, while sending request body
可以参考 reactor.netty.http.client.PrematureCloseException: Connection prematurely closed BEFORE response解决方案 和 Connection has been closed BEFORE response异常 这两篇博客;
上面的代码都已解决!后面如果遇到其他问题会继续补充。
更多推荐
所有评论(0)