web-dev-qa-db-ja.com

RestTemplateインターセプター

現在、HandlerInterceptorAdapterを組み込もうとしていますが、登録されておらず、他の回答と比較するのは難しいです。そして、私はWebMvcConfigureAdapterが非推奨であることを知っています。一部のバージョン管理は、プロジェクトの範囲を制御できないため、以下の使用法の仕様を参照してください。

誰かがRestTemplateにインターセプターを組み込むことに関するガイダンスを提供していただけますか(これはClientHttpRequestInterceptorではありません)。

メイン:

@SpringBootApplication
@EnableRetry
public class Application extends SpringBootServletInitializer {

  public static void main(String[] args) {

   ApplicationContext ctx = SpringApplication.run(Application.class, args);

  }


  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder applicationBuilder) {

    return applicationBuilder.sources(Application.class);

  }

  @Bean
  private RestTemplate restTemplate(){
    Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("redacted", 8080));

    SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
    simpleClientHttpRequestFactory.setProxy(proxy);
    simpleClientHttpRequestFactory.setOutputStreaming(false);

    RestTemplate template = new RestTemplate();
    template.setErrorHandler(new MyResponseErrorHandler());

    return template;
  }
}

インターセプター:com.example.foo.config.request.interceptor

@Component
public class MyInterceptor extends HandlerInterceptorAdapter {

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println("INTERCEPTED");
    return super.preHandle(request, response, handler);
  }
}

InterceptorConfig:com.example.foo.config.request.interceptor

@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter  {

  @Bean
  MyInterceptor myInterceptor() {
    return new MyInterceptor();
  }

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    super.addInterceptors(registry);
    System.out.println("Adding interceptor");
    registry.addInterceptor(myInterceptor());
  }

}

「インターセプターの追加」はログに記録されるため、構成がスキャンされていることがわかります。インターセプターロジックをログに記録できません。

使用:

  • スプリングブートv1.5.15
  • 春バージョン:4.3.18.RELEASE
3
soulshined

HandlerInterceptorAdapterは、@Controllerまたは@RestControllerに適用される実装です。 RestTempleteの実装ではありません。

RestTempleteに適用するには、ClientHttpRequestInterceptorを使用する必要があります。

例。

@Component
public class CustomInterceptor implements ClientHttpRequestInterceptor {
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        // ... 
    }
}
@Configuation
public class RestTempleteConfig {

    // ...
    @Autowired
    private CustomInterceptor customInterceptor;

    @Bean
    public RestTemplate restTemplate(){
        RestTemplate template = new RestTemplate();
        List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
        template.add(customInterceptor);
        return template;
    }
}
1
WonChul Heo

@WonChulHeoが指摘したように、HandlerInterceptorAdapterRestTemplateとともに使用することはできません。 ClientHttpRequestInterceptorのみ。なぜ正確にHandlerInterceptorAdapterが必要なのかは明確ではありません。リクエストのインターセプトの事実をログに記録しようとしていることがわかります。そして、ClientHttpRequestInterceptorは同じことを完全に行うことができます-以下の私の動作例を確認してください。

追伸コードにエラーがあります-_@Bean_メソッドにprivateアクセスを使用することはできません-private RestTemplate restTemplate() {を確認してください...

_@Slf4j
@RestController
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class)
                .bannerMode(Banner.Mode.OFF)
                .run(args);
    }

    @GetMapping("/users/{id}")
    public User get(@PathVariable int id) {
        log.info("[i] Controller: received request GET /users/{}", id);
        return new User(id, "John Smith");
    }

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder templateBuilder) {
        ClientHttpRequestFactory requestFactory = new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory());
        return templateBuilder
                .interceptors((request, bytes, execution) -> {
                    URI uri = request.getURI();
                    HttpMethod method = request.getMethod();

                    log.info("[i] Interceptor: requested {} {}", method, uri);
                    log.info("[i] Interceptor: request headers {}", request.getHeaders());

                    ClientHttpRequest delegate = requestFactory.createRequest(uri, method);
                    request.getHeaders().forEach((header, values) -> delegate.getHeaders().put(header, values));

                    ClientHttpResponse response = delegate.execute();
                    log.info("[i] Interceptor: response status: {}", response.getStatusCode().name());
                    log.info("[i] Interceptor: response headers: {}", response.getHeaders());
                    String body = StreamUtils.copyToString(response.getBody(), Charset.defaultCharset());
                    log.info("[i] Interceptor: response body: '{}'", body);

                    return response;
                })
                .rootUri("http://localhost:8080")
                .build();
    }

    @Bean
    ApplicationRunner run(RestTemplate restTemplate) {
        return args -> {
            ResponseEntity<User> response = restTemplate.getForEntity("/users/{id}", User.class, 1);
            if (response.getStatusCode().is2xxSuccessful()) {
                log.info("[i] User: {}", response.getBody());
            } else {
                log.error("[!] Error: {}", response.getStatusCode());
            }
        };
    }
}
_
_@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
}
_
0
Cepr0

HandlerInterceptorAdapterは、サーバー側(つまりRestController)がサーバーがHTTPリクエストを処理するときにいくつかの重要なイベントをインターセプトするためのもので、使用されるHTTPクライアント(例:RestTemplate)とは関係ありません。

RestTemplateをHTTPクライアントとして使用し、送信直前のリクエストと受信直後の応答をインターセプトする場合は、ClientHttpRequestInterceptorを使用する必要があります。

ClientHttpRequestInterceptorよりも柔軟な方法でリクエストとレスポンスをインターセプトしようとしています。

上記のコメントから、それが処理できない実際のユースケースは何ですか? ClientHttpRequestInterceptorは、要求と応答をインターセプトするための複雑なロジックを実装するのに十分な柔軟性を備えていると思います。あなたの質問はあなたがどのように傍受する必要があるかについての情報を提供していませんので、私はClientHttpRequestInterceptorが何を提供できるかを示すための一般的な例しか提示できません。

インターセプターを使用するようにRestTemplateを構成するには:

_RestTemplate rt = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptors= new ArrayList<ClientHttpRequestInterceptor>();
inteceptors.add(new MyClientHttpRequestInterceptor());
_

そして、ClientHttpRequestInterceptorは次のようになります。

_public class MyClientHttpRequestInterceptor implements ClientHttpRequestInterceptor{

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
            throws IOException {

        //The HTTP request and its body are intercepted here which you can log them or modify them. e.g.
        System.out.println("Log the HTTP request header: " + request.getHeaders());

        //Modify the HTTP request header....
        request.getHeaders().add("foo", "fooValue");

        //Throw exception if you do not want to send the HTTP request

        //If it is at the end of the interceptor chain , call execution.execute() to confirm sending the HTTP request will return the response in ClientHttpResponse
        //Otherwise, it will pass the request to the next interceptor in the chain to process
        ClientHttpResponse response= execution.execute(request, body);

        //The HTTP response is intercepted here which you can log them or modify them.e.g.
        System.out.println("Log the HTTP response header: " + response.getHeaders());

        //Modify the HTTP response header
        response.getHeaders().add("bar", "barValue");

        return response;
    }
}
_

ClientHttpRequestInterceptorのチェーンを構成することもできます。これにより、いくつかの複雑な要求および応答インターセプトロジックを多数の小さな再利用可能なClientHttpRequestInterceptorに分割できます。 責任の連鎖 の設計パターンで設計されており、そのAPIエクスペリエンスはServletFilter#doFilter()と非常によく似ています。

0
Ken Chan