微服务项目中很多网关的功能真的强大,从路由,认证,鉴权到修改请求和响应内容,真正体会到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异常 这两篇博客;

上面的代码都已解决!后面如果遇到其他问题会继续补充。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐