복붙노트

[SPRING] Cloud API 게이트웨이에 대한 응답 본문에 데이터를 추가하는 방법

SPRING

Cloud API 게이트웨이에 대한 응답 본문에 데이터를 추가하는 방법

일부 인증 로직을 클라우드 API 게이트웨이에 추가하고 있습니다. 나는 GatewayFilter를 추가했다.

import java.util.List;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.HttpStatus;
import org.springframework.util.CollectionUtils;
import org.springframework.util.PatternMatchUtils;
import org.springframework.web.server.ServerWebExchange;

import reactor.core.publisher.Mono;

public class AuthorizationFilter implements GatewayFilter {
  @Override
  public Mono<Void> filter(
    ServerWebExchange exchange, GatewayFilterChain chain) {
    List<String> authorization = exchange.getRequest().getHeaders().get("Authorization");
    if (CollectionUtils.isEmpty(authorization) &&
      !PatternMatchUtils.simpleMatch(URL_WITHOUT_AUTH, exchange.getRequest().getURI().toString())) {
      exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
      //Add some custom data in body of the response
      return exchange.getResponse().setComplete();
    }
    String token = authorization.get(0).split(" ")[1];
    // token validation
    return chain.filter(exchange);
  }
}

하지만 응답 본문에 일부 데이터를 추가 할 수는 없습니다. 어떻게 작동하는지 그리고 어떻게 사용자 정의 할 수 있는지 알아 주시겠습니까?

추신 플럭스를 사용하여 응답으로 일부 데이터를 추가하려고하지만 작동하지 않습니다.

 DataBuffer b = exchange.getResponse().bufferFactory().allocateBuffer(256);
      b.write("12345".getBytes());
      return exchange.getResponse().writeWith(s -> Flux.just(b));

내가 뭘 잘못하고있어?

해결법

  1. ==============================

    1.봄 녀석들의 도움을 받아, 나는 일하게 만들 수 있었다. 따라서 응답에 직접 작성하는 대신 사용자 정의 예외를 던져 올바르게 처리해야했습니다.

    봄 녀석들의 도움을 받아, 나는 일하게 만들 수 있었다. 따라서 응답에 직접 작성하는 대신 사용자 정의 예외를 던져 올바르게 처리해야했습니다.

    @Bean
    public ErrorWebExceptionHandler myExceptionHandler() {
      return new MyWebExceptionHandler();
    }
    
    public class MyWebExceptionHandler implements ErrorWebExceptionHandler {
      @Override
      public Mono<Void> handle(
        ServerWebExchange exchange, Throwable ex) {
        byte[] bytes = "Some text".getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
        return exchange.getResponse().writeWith(Flux.just(buffer));
      }
    }
    
  2. ==============================

    2.ServerHttpResponseDecorator를 사용하여 응답을 수정해야합니다.

    ServerHttpResponseDecorator를 사용하여 응답을 수정해야합니다.

    코드는 다음과 같아야합니다.

    import java.util.List;
    
    import org.reactivestreams.Publisher;
    import org.springframework.cloud.gateway.filter.GatewayFilter;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.http.HttpStatus;
    import org.springframework.util.CollectionUtils;
    import org.springframework.util.PatternMatchUtils;
    import org.springframework.web.server.ServerWebExchange;
    import org.springframework.http.server.reactive.ServerHttpResponse;
    import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
    import org.springframework.core.io.buffer.DataBuffer;
    import org.springframework.core.io.buffer.DataBufferFactory;
    import org.springframework.core.Ordered;
    import org.springframework.stereotype.Component;
    
    import reactor.core.publisher.Mono;
    
    public class AuthorizationFilter implements GatewayFilter {
      @Override
      public Mono<Void> filter(
        ServerWebExchange exchange, GatewayFilterChain chain) {
        List<String> authorization = exchange.getRequest().getHeaders().get("Authorization");
        if (CollectionUtils.isEmpty(authorization) &&
          !PatternMatchUtils.simpleMatch(URL_WITHOUT_AUTH, exchange.getRequest().getURI().toString())) {
          exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
    
          ServerHttpResponse originalResponse = exchange.getResponse();
          DataBufferFactory bufferFactory = originalResponse.bufferFactory();
          ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                    return super.writeWith(fluxBody.map(dataBuffer -> {
                        // probably should reuse buffers 
                        byte[] content = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(content);
                        byte[] uppedContent = new String(content, Charset.forName("UTF-8")).toUpperCase().getBytes();
                        return bufferFactory.wrap(uppedContent);
                    }));
                }
                return super.writeWith(body); // if body is not a flux. never got there.
            }           
          };
          return chain.filter(exchange.mutate().response(decoratedResponse).build()); // replace response with decorator
        }
        String token = authorization.get(0).split(" ")[1];
        // token validation
        return chain.filter(exchange);
      }
    }
    

    여기서 완전한 예를 찾을 수 있습니다.

  3. from https://stackoverflow.com/questions/48491098/how-to-add-some-data-in-body-of-response-for-cloud-api-gateway by cc-by-sa and MIT license