当前位置: 首页 > 知识库问答 >
问题:

WebClient:等待API中的阻塞调用以执行新调用

刘骏祥
2023-03-14

我目前正在制作一个微服务来为我们的自动化测试环境创建测试用户。该数据库可以通过另一个API访问,因此为了创建测试用户,我需要执行对该API的调用。

应创建测试用户,然后在执行测试后处理。测试用户的标识符是SSN(国家标识符数字),每个公民都是唯一的。我的API/microservice使用生成的SSN生成一个新用户,并应通过API将其发布到数据库,以控制数据库的后端服务。此后端服务不是被动的。

问题是,在数据库中,已有许多现有用户被手动执行的其他测试使用。现有的测试用户不能被篡改,因此我需要验证生成的SSN是否已经存在于数据库中。

我的做法如下:

generate a new ssn
while(ssn exists in db){
    generate new ssn
}
post generated user to db

但是,在放置时。block()检查用户是否存在(错误做法,我知道…)程序在死锁中停止,什么也没有发生。

我的控制器:

@ResponseBody
@PostMapping("normal")
public Mono<User> createNormalUser() throws Exception {
    return userService.createNormalUser();
}

@ResponseBody
@GetMapping("{ssn}")
public Mono<User> getUserBySSN(@PathVariable String ssn){
    return userService.getUserBySsn(ssn);
}

我的服务:

public Mono<User> createNormalUser(){
   String ssn = generateNewSsnNotInDB();

   Mono<UserResource> newUserMono = Mono.just(
           UserResource.builder()
                   .ssn(ssn)
                   .email(ssn + "-test@somedomain.com")
                   .state("NORMAL")
                   .preferred2FaMethod("some2FAMethod")
                   .build()
   );
   return postUser(newUserMono)
           .then(updatePassword(ssn))
           .then(setState(ssn, "NORMAL"));
}

private String generateNewSsnNotInDB() {
   String ssn;
   boolean userExists = false;

   do {
       ssn = ssnGenerator.generateOneValidSsnOnDate(ssnGenerator.generateRandomSsnDate());
       userExists = checkIfUserExists(ssn);
   } while (userExists);
   return ssn;
}

private boolean checkIfUserExists(String ssn) {
   User user;
   try {
       user = getUserBySsn(ssn).share().block();
       return true;
   } catch (WebClientResponseException.NotFound exception) {
       return false;
   }
}

public Mono<User> getUserBySsn(String ssn) {
   return webClient.get()
           .uri(userBySsnURI(ssn))
           .retrieve()
           .bodyToMono(User.class);
}

public Mono<User> postUser(Mono<UserResource> userMono) {
   return webClient.post()
           .uri(setUserURI())
           .body(userMono, UserResource.class)
           .retrieve()
           .bodyToMono(User.class);
}

public Mono<User> postUser(User user) {
   user.setPid(generateNewSsnNotInDB());
   UserResource res = UserResource.builder()
           .ssn(user.getPid())
           .email(user.getEmail())
           .phoneNumber(user.getPhoneNumber())
           .state(user.getState())
           .preferred2FaMethod(user.getPreferred2FaMethod())
           .password(user.getPassword())
           .build();
   log.info("Resource generated in post-user is: " + res.toString());
   return postUser(Mono.just(res));
}

public Mono<User> updatePassword(String ssn) {
   Mono<User> user = Mono.just(User.builder()
           .pid(ssn)
           .password("password01")
           .build());
   return webClient.patch()
           .uri(setUpdatePasswordURI())
           .body(user, User.class)
           .retrieve()
           .bodyToMono(User.class);
}

private Mono<User> setState(String ssn, String state) {
   return webClient.put()
           .uri(updateStateURI(ssn, state))
           .retrieve()
           .bodyToMono(User.class);
}

我在createNormalUser函数中链接了调用,因为后端需要这个序列来为用户设置所需的属性。我不确定为什么这是必需的序列,改变这不是我范围的一部分。

我还省略了一些可能与此问题无关的函数。

有人能帮我找到正确的方向吗?如何用Check IfUsersExist执行呼叫,然后发布用户?我已经想了一个星期了,但运气不好。

最奇怪的是,如果我首先用一个有效的ssn调用getUser,那么postUser就可以正常工作。如果我尝试在不首先调用getUser的情况下调用posture,它会在上死锁。block()。

共有1个答案

叶嘉颖
2023-03-14

请避免以下调用和用户链接调用(createNormalUser()generateNewSsnNotInDB()已更新并删除了checkIfUserExists()):

public Mono<User> createNormalUser(){
    Mono<UserResource> newUserMono = generateNewSsnNotInDB().map( ssn ->
           UserResource.builder()
                   .ssn(ssn)
                   .email(ssn + "-test@somedomain.com")
                   .state("NORMAL")
                   .preferred2FaMethod("some2FAMethod")
                   .build()
   );
   return postUser(newUserMono)
           .then(updatePassword(ssn))
           .then(setState(ssn, "NORMAL"));
}

private Mono<String> generateNewSsnNotInDB() {
   return Mono.just(ssnGenerator.generateOneValidSsnOnDate(ssnGenerator.generateRandomSsnDate()))
      .flatMap(ssn -> getUserBySsn(ssn))
      .switchIfEmpty(Mono.defer(() -> generateNewSsnNotInDB()));
}

public Mono<User> getUserBySsn(String ssn) {
   return webClient.get()
           .uri(userBySsnURI(ssn))
           .retrieve()
           .bodyToMono(User.class);
}

public Mono<User> postUser(Mono<UserResource> userMono) {
   return webClient.post()
           .uri(setUserURI())
           .body(userMono, UserResource.class)
           .retrieve()
           .bodyToMono(User.class);
}

public Mono<User> postUser(User user) {
   user.setPid(generateNewSsnNotInDB());
   UserResource res = UserResource.builder()
           .ssn(user.getPid())
           .email(user.getEmail())
           .phoneNumber(user.getPhoneNumber())
           .state(user.getState())
           .preferred2FaMethod(user.getPreferred2FaMethod())
           .password(user.getPassword())
           .build();
   log.info("Resource generated in post-user is: " + res.toString());
   return postUser(Mono.just(res));
}

public Mono<User> updatePassword(String ssn) {
   Mono<User> user = Mono.just(User.builder()
           .pid(ssn)
           .password("password01")
           .build());
   return webClient.patch()
           .uri(setUpdatePasswordURI())
           .body(user, User.class)
           .retrieve()
           .bodyToMono(User.class);
}

private Mono<User> setState(String ssn, String state) {
   return webClient.put()
           .uri(updateStateURI(ssn, state))
           .retrieve()
           .bodyToMono(User.class);
}
 类似资料:
  • 我正在使用Spring Webflux和Spring数据jpa,使用PostgreSql作为后端数据库。我不想在进行诸如查找和保存之类的db调用时阻塞主线程。为了实现同样的目标,我在Controller类中有一个主调度器,在服务类中有一个jdbcScheduler。 我定义它们的方式是: 现在,当在我的服务层中进行获取/保存调用时,我这样做: 在控制器中,我执行以下操作: 这是正确的吗?和/或有更

  • 本文向大家介绍node.js回调函数之阻塞调用与非阻塞调用,包括了node.js回调函数之阻塞调用与非阻塞调用的使用技巧和注意事项,需要的朋友参考一下 首先,node.js作为javascript运行平台,它采用了事件驱动和异步编程的方式,通过事件注册和异步函数,开发人员可以提高资源利用率,服务器的性能也能得到改善。其次,对于前端人来说,node.js作为js的运行平台,我们可以通过编写系统级或者

  • 我有一个springboot项目,它使用springboot RestTemplate。我们已经从1.5.3转移到了SpringBoot2.0.1,并且我们正在尝试通过使用WebClient将rest调用异步化。我们过去使用Resttemplate处理接收到的字符串,如下所示。但是WebClient只返回单点或通量数据。如何将数据作为字符串获取。已经尝试了block()方法,但它执行异步调用。 使

  • 我完全混淆了,,。 哪个是阻塞,哪个不是? 我的意思是如果我使用父进程是否等待子进程返回/才继续执行。 如何影响这些调用?

  • 在上一节中,我们看到了 take Effect 让我们可以在一个集中的地方更好地去描述一个非常规的流程。 重温一下登录流程示例: function* loginFlow() { while(true) { yield take('LOGIN') // ... perform the login logic yield take('LOGOUT') // ...

  • 问题内容: 我过去一直在努力,今天一直在努力的事情是阻止API / AJAX继续进行,直到您收到响应为止。目前,我正在使用Facebook API。我需要从调用中获取响应,然后将其返回,但是正在发生的事情是,在我从未从API调用中获取响应之前,我的函数正在返回。我知道为什么会这样,我只是想不出如何预防!这是我的代码… // -----编辑 我注意到有人建议这样的事情… 但这返回未定义 //根据更新