标签: spring-webclient

无法找到“org.springframework.web.reactive.function.client.WebClient”类型的 Bean

我正在使用本手册https://golb.hplar.ch/2018/01/Sending-Web-push-messages-from-Spring-Boot-to-Browsers.html的示例来研究推送通知。我面临的问题是,当我运行应用程序时,出现错误

    Parameter 1 of constructor in ru.stepanb.MetricPushingApplication.push.PushChuckJokeService required could not be found. 

    Consider defining a bean of type 'org.springframework.web.reactive.function.client.WebClient' in your configuration.
Run Code Online (Sandbox Code Playgroud)
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Service;
    import org.springframework.web.reactive.function.client.WebClient;

    @Service
    public class PushChuckJokeService {

      private final FcmClient fcmClient;

      private final WebClient webClient;

      private int seq = 0;
 
      public PushChuckJokeService(FcmClient fcmClient, WebClient webClient) {
         this.fcmClient = fcmClient;
         this.webClient = webClient;
      }

      @Scheduled(fixedDelay = 30_000)
      public void sendChuckQuotes() {
        IcndbJoke joke = 
        this.webClient.get().uri("http://api.icndb.com/jokes/random")
        .retrieve().bodyToMono(IcndbJoke.class).block();
         try {
          sendPushMessage(joke);
         } 
        catch (InterruptedException | ExecutionException …
Run Code Online (Sandbox Code Playgroud)

spring-boot spring-webclient

3
推荐指数
1
解决办法
3万
查看次数

配置 Spring WebFlux WebClient 以使用自定义线程池

是否可以将 WebClient 配置为使用 reactor-http-nio 线程池以外的自定义线程池(使用 Netty 时)?如果可能,我们能否以某种方式限制该自定义线程池仅在特定处理器内核上运行?

spring-boot project-reactor spring-webflux spring-webclient

3
推荐指数
1
解决办法
3811
查看次数

在测试中替换 OAuth2 WebClient

我有一个小型 Spring Boot 2.2 批次,用于写入 OAuth2 REST API。

我已经能够配置以下WebClienthttps://medium.com/@asce4s/oauth2-with-spring-webclient-761d16f89cdd并且它按预期工作。

    @Configuration
    public class MyRemoteServiceClientOauth2Config {

        @Bean("myRemoteService")
        WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations) {
            ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
                    new ServerOAuth2AuthorizedClientExchangeFilterFunction(
                            clientRegistrations,
                            new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
            oauth.setDefaultClientRegistrationId("myRemoteService");

            return WebClient.builder()
                    .filter(oauth)
                    .build();
        }

    }
Run Code Online (Sandbox Code Playgroud)

但是,现在我想为我的批次编写集成测试,并且我想避免使用“真实”授权服务器来获取令牌:如果外部服务器关闭,我不希望我的测试失败。我希望我的测试是“自主的”。

在我的测试过程中,我调用的远程服务被mockserver假的服务所取代。

在这种情况下,最佳做法是什么?

  • 对我有用的是仅在测试之外启用上述配置@Profile("!test")并使用 运行我的测试@ActiveProfiles("test")。我还在测试中导入了测试特定配置:
    @Configuration
    @Profile("test")
    public class BatchTestConfiguration {

        @Bean("myRemoteService")
        public WebClient webClientForTest() {

            return WebClient.create();
        }

    }
Run Code Online (Sandbox Code Playgroud)

但我觉得必须添加@Profile("!test")我的生产配置并不是很好。

  • 有没有一种“更干净”的方法来替换我正在使用的 WebClient bean,通过调用我的假远程服务而无需先尝试获取令牌的方法?我尝试@Primary在我的 webClientForTest bean 上添加一个,但它不起作用:生产 bean 仍然启用,并且出现异常:

没有类型为“org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository”的合格 bean

这是生产bean需要的参数类型 …

spring-boot spring-webclient

3
推荐指数
1
解决办法
3622
查看次数

使用 Spring WebClient 重试时添加新标头

webclientbuilder.baseUrl(url)
                .defaultHeaders(headers -> headers.addAll(requestHeader))
                .build()
                .post()
                .uri("/uri")
                .bodyValue(data)
                .exchange()
                .flatMap(response  -> {
                                if(response.statusCode() == HttpStatus.UNAUTHORIZED){
                                                //retry with updated token in header
                                }
                })
                //return bodyToMono of specific object when retry is done or if
                //response status is 2xx
Run Code Online (Sandbox Code Playgroud)

任何有关如何处理此问题的建议将不胜感激!正如评论所说,如果 statusCode 为 UNAUTHORIZED,并且如果 statusCode 为 2xx,则在重试 post 请求之前,我需要将新令牌添加到标头,然后返回 bodyToMono。

spring request-headers spring-retry spring-boot spring-webclient

3
推荐指数
1
解决办法
2604
查看次数

Spring WebClient - 在发生 HTTP 错误(4xx、5xx)时如何访问响应正文?

我想将异常从“数据库”REST API 重新抛出到“后端”REST API,但我丢失了原始异常的消息。

这是我通过 Postman 从“数据库”REST API 获得的信息:

{
    "timestamp": "2020-03-18T15:19:14.273+0000",
    "status": 400,
    "error": "Bad Request",
    "message": "I'm DatabaseException (0)",
    "path": "/database/api/vehicle/test/0"
}
Run Code Online (Sandbox Code Playgroud)

这部分还可以。

这是我通过 Postman 从“后端”REST API 获得的信息:

{
    "timestamp": "2020-03-18T15:22:12.801+0000",
    "status": 400,
    "error": "Bad Request",
    "message": "400 BAD_REQUEST \"\"; nested exception is org.springframework.web.reactive.function.client.WebClientResponseException$BadRequest: 400 Bad Request from GET http://localhost:8090/database/api/vehicle/test/0",
    "path": "/backend/api/vehicle/test/0"
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,原始的“消息”字段丢失了。

我用:

  • 春季启动 2.2.5.RELEASE
  • spring-boot-启动器-web
  • spring-boot-starter-webflux

后端和数据库从 Tomcat 开始(web 和 webflux 在同一应用程序中)。

这是后端:

    @GetMapping(path = "/test/{id}")
    public Mono<Integer> test(@PathVariable String id) {
        return …
Run Code Online (Sandbox Code Playgroud)

java spring-boot spring-webflux spring-webclient

3
推荐指数
2
解决办法
2万
查看次数

反应式编程:Spring WebFlux:如何构建微服务调用链?

Spring Boot应用:

a@RestController接收以下有效负载:

{
  "cartoon": "The Little Mermaid",
  "characterNames": ["Ariel", "Prince Eric", "Sebastian", "Flounder"]
}
Run Code Online (Sandbox Code Playgroud)

我需要按以下方式处理它:

  1. 获取每个角色名称的唯一 ID:对“卡通人物”微服务进行 HTTP 调用,该服务按名称返回 id
  2. 转换控制器接收到的数据:将角色名称替换为上一步从“卡通人物”微服务接收到的适当 ID。 { "cartoon": "The Little Mermaid", "characterIds": [1, 2, 3, 4] }

  3. 使用转换后的数据向“cartoon-db”微服务发送 HTTP POST 请求。

  4. 将“cartoon-db”的响应映射到作为控制器返回值的内部表示。

我遇到的问题:

Reactive Programming我需要使用(非阻塞\异步处理)和Spring WebFluxMono| Flux)的范例来实现所有这些步骤Spring Reactive WebClient- 但我对该堆栈的经验为零,试图尽可能多地阅读它,再加上谷歌搜索很多但是仍然有很多未解答的问题,例如:

Q1 . 我已经配置了响应式 webClient,向“卡通人物”微服务发送请求:

      public Mono<Integer> getCartoonCharacterIdbyName(String characterName) {
    return WebClient.builder().baseUrl("http://cartoon-characters").build()
        .get()
        .uri("/character/{characterName}", characterName)
        .retrieve()
        .bodyToMono(Integer.class);
  }
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我有一个卡通人物名称列表,对于每个角色我需要调用getCartoonCharacterIdbyName(String name)方法,我不确定串联调用它的正确选项,相信正确的选项:并行执行。

写了如下方法: …

reactive-programming spring-boot reactive spring-webflux spring-webclient

3
推荐指数
1
解决办法
5980
查看次数

使用Spring WebClient在java中上传文件

我正在尝试从普通的 HttpPost 方法迁移到 Spring WebClient,并且我有一个 API 接受两个文件(一个 JSON 和一个 PDF)进行上传。

我尝试发送如下文件,但收到 500 内部服务器错误而不是 200 OK。

String jsonData ="";
ByteArrayOutputStream file;

MultipartBodyBuilder builder = new MultipartBodyBuilder();
String header1 = String.format("form-data; name=%s; filename=%s", "attach", "file.pdf");
String header2 = String.format("form-data; name=%s; filename=%s", "jsonfile", "jsonfile.json");

// This line is causing the problem, Am I making a mistake here?
builder.part("attach", file.toByteArray()).header("Content-Disposition", header1);
// This line works fine.
builder.part("jsonfile", jsonData.getBytes()).header("Content-Disposition", header2);

WebClient webClient = WebClient.create("a url");

        byte[] fileContent = null;
        try {
            fileContent = webClient.post()
                .body(BodyInserters.fromMultipartData(builder.build())) …
Run Code Online (Sandbox Code Playgroud)

java upload spring spring-webclient

3
推荐指数
1
解决办法
1万
查看次数

WebClient 在 JUnit 中导致“java.lang.IllegalStateException:执行器不接受任务”

我想在 JUnit 测试框架内使用反应式编程来对远程 REST API 进行系统测试。

我因此写道:

  @Test
  void testWebClient() {
    WebClient webClient = WebClient.builder()
        .baseUrl(GITHUB_API_BASE_URL)
        .defaultHeader(HttpHeaders.CONTENT_TYPE, GITHUB_V3_MIME_TYPE)
        .defaultHeader(HttpHeaders.USER_AGENT, USER_AGENT)
        .filter(ExchangeFilterFunctions
            .basicAuthentication(appProperties.getGithub().getUsername(),
                appProperties.getGithub().getToken()))
        .build();

    var response = webClient.get()
        .uri("/user/repos?sort={sortField}&direction={sortDirection}",
            "updated", "desc")
        .exchange()
            .doOnError(e -> {
              System.out.println(e.toString());
            })
            .subscribe(r -> {
              System.out.println(r  );
            });
  }
Run Code Online (Sandbox Code Playgroud)

获取我所有的 github 存储库。我不断发现这个错误:

java.lang.IllegalStateException: executor not accepting a task
Run Code Online (Sandbox Code Playgroud)

直到在“.exchange()”之后添加“.block()”以同步进行调用,一切开始正常工作。

我怀疑 JUnit 会启动一个特殊的线程上下文或类似的东西。你知道发生了什么吗?

多谢

java spring spring-webclient

3
推荐指数
1
解决办法
4278
查看次数

Spring WebClient:重试中调用方法

我一直在寻找以下用例的解决方案但没有成功,我希望有人可以提供帮助:

假设以下用例。我需要调用客户 Api( customerApi),而该 api 需要一个Bearer令牌,当我调用时该令牌可能已过期customerApi。如果令牌已过期,则customerApi返回401响应。

我想做的是,如果我收到一个401并调用该方法来获取新Bearer令牌,则仅重试一次。如果重试仍然返回401,我需要抛出一个Exception

获取token的方法Bearer

private String getToken() {
    return oAuthService.getToken();
}
Run Code Online (Sandbox Code Playgroud)

webClient调用customerApi(customerWebClient是用 ) 创建的 bean 的用法WebClient.Builder

public Customer getCustomerById(String customerId, String token) {
        return customerWebClient.get()
            .uri("myurl/customers/{customerId}, customerId)
            .headers(httpHeaders -> {
                httpHeaders.add(HttpHeaders.AUTHORIZATION, "Bearer " + token);
            })
            .retrieve()
            .bodyToMono(Customer.class)
            .onErrorResume(WebClientResponseException.NotFound.class, notFound ->
                        Mono.error(new MyCustomException()))
            .block();
    }
Run Code Online (Sandbox Code Playgroud)

看来retryWhen只能用超时来升级了。所以我希望有人知道如何实现这个用例^^

感谢您的帮助 :)

编辑 …

reactor-netty spring-webflux spring-webclient

3
推荐指数
1
解决办法
2906
查看次数

ServiceImpl 构造函数中的 Spring Boot WebClient Builder 初始化

我正在尝试遵循使用 WebClient Builder 自动装配 Webclient 的最佳实践,但很少混淆。

这是我的主要应用程序,我正在其中生成一个 Webclient Builder 并在我的一个服务类中自动装配它

 @SpringBootApplication
    public class MyApplication {
        @Bean
        public WebClient.Builder getWebClientBuilder() {
            return WebClient.builder();
        }
    
        public static void main(String[] args) {
            SpringApplication.run(MyApplication.class, args);
        }}


ServiceImpl Class

    public class MyServiceImpl implements MyService {
        private static final String API_MIME_TYPE = "application/json";
        private static final String API_BASE_URL = "http://localhost:8080";
        private static final String USER_AGENT = "Spring 5 WebClient";
        private static final Logger logger = LoggerFactory.getLogger(MyServiceImpl.class);
    
        @Autowired
        private WebClient.Builder webClientBuilder;
    
        @Override
        public Mono<Issue> createIssue(Fields field) { …
Run Code Online (Sandbox Code Playgroud)

java spring-boot spring-webflux spring-webclient

3
推荐指数
1
解决办法
1807
查看次数