Spring - Cloud - Gateway 가 multipart / form - data 를 가 져 올 때 정상적으로 가 져 올 수 없습니다.

우리 회 사 는 최근 spring Cloud2. X 를 업그레이드 하고 있 습 니 다. Spring - Cloud - Gateway 를 공식 추천 으로 사용 하기 때문에 최근 에 Spring - Cloud - Gateway 를 연구 하고 있 습 니 다. 그러나 실제 개발 과정 에서 여러 가지 문제 가 발생 했 습 니 다. 그 중에서 가장 오래 걸 린 것 은 multipart / form - data 에 있 는 json 문자열 을 얻 기 위해 인터넷 에서 여러 가지 해결 방안 을 시 도 했 지만 성공 적 으로 얻 지 못 했 습 니 다.결국 GitHub 의 issue 에서 큰 사람 을 찾 아 이 문 제 를 해결 했다. 쓸데없는 말 은 하지 않 고 코드 를 직접 올 렸 다.
package com.cango.center.gateway.filter;

import java.util.Collections;
import java.util.List;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.multipart.FormFieldPart;
import org.springframework.http.codec.multipart.Part;
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.reactive.function.server.HandlerStrategies;
import org.springframework.web.server.ServerWebExchange;

import com.XX.center.gateway.entity.GatewayContext;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 *       .
 *
 * @author zyb
 */
@Component
public class GatewayContextFilter extends BaseFilter {

    /**
     * default HttpMessageReader.
     */
    private static final List> MESSAGE_READERS = HandlerStrategies.withDefaults().messageReaders();

    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        final ServerHttpRequest request = exchange.getRequest();
        final String path = request.getPath().pathWithinApplication().value();
        final GatewayContext gatewayContext = new GatewayContext();
        gatewayContext.setPath(path);
        exchange.getAttributes().put(GatewayContext.CACHE_GATEWAY_CONTEXT, gatewayContext);
        return DataBufferUtils.join(exchange.getRequest().getBody()).flatMap(dataBuffer -> {
            DataBufferUtils.retain(dataBuffer);
            final Flux cachedFlux = Flux.defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
            final ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
                @Override
                public Flux getBody() {
                    return cachedFlux;
                }
            };
            final ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build();
            return cacheBody(mutatedExchange, chain, gatewayContext);
        });
    }

    @SuppressWarnings("unchecked")
    private Mono cacheBody(ServerWebExchange exchange, GatewayFilterChain chain, GatewayContext gatewayContext) {
        final HttpHeaders headers = exchange.getRequest().getHeaders();
        if (headers.getContentLength() == 0) {
            return chain.filter(exchange);
        }
        final ResolvableType resolvableType;
        if (MediaType.MULTIPART_FORM_DATA.isCompatibleWith(headers.getContentType())) {
            resolvableType = ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, Part.class);
        } else {
            resolvableType = ResolvableType.forClass(String.class);
        }
        return MESSAGE_READERS.stream().filter(reader -> reader.canRead(resolvableType, exchange.getRequest().getHeaders().getContentType())).findFirst()
            .orElseThrow(() -> new IllegalStateException("no suitable HttpMessageReader.")).readMono(resolvableType, exchange.getRequest(), Collections.emptyMap()).flatMap(resolvedBody -> {
                if (resolvedBody instanceof MultiValueMap) {
                    final Part partInfo = (Part) ((MultiValueMap) resolvedBody).getFirst("info");
                    if (partInfo instanceof FormFieldPart) {
                        gatewayContext.setRequestBody(((FormFieldPart) partInfo).value());
                    }
                } else {
                    gatewayContext.setRequestBody((String) resolvedBody);
                }
                return chain.filter(exchange);
            });
    }
}

참고:https://github.com/xurui8691413/sping-cloud-gateway-read-multipart-filter/blob/master/spring-cloud-gateway-sample
도움 이 됐 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기