WebFlux 扩展未检索第二个请求

Posted

技术标签:

【中文标题】WebFlux 扩展未检索第二个请求【英文标题】:WebFlux expand is not retrieving the second request 【发布时间】:2020-09-24 07:54:01 【问题描述】:

我正在尝试使用 Spring 的 webflux 创建一个 http 端点,以使用 Github 的 api 流式传输 github 用户。我尝试执行here 和here 所描述的操作,但扩展似乎没有从 github 的 api 获取结果的第二页。我究竟做错了什么? 这是我目前拥有的代码:

@RestController
@RequestMapping("/user")
public class GithubUserController 

  private static final String GITHUB_API_URL = "https://api.github.com";

  private final WebClient client = WebClient.create(GITHUB_API_URL);

  @GetMapping(value = "/search/stream", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
  public Flux<GithubUser> search(
      @RequestParam String location,
      @RequestParam String language,
      @RequestParam String followers) 

    return fetchUsers(
            uriBuilder ->
                uriBuilder
                    .path("/search/users")
                    .queryParam(
                        "q",
                        String.format(
                            "location:%s+language:%s+followers:%s", location, language, followers))
                    .build())
        .expand(
            response -> 
              var links = response.headers().header("link");
              Pattern p = Pattern.compile("<(.*)>; rel=\"next\".*");
              for (String link : links) 
                Matcher m = p.matcher(link);
                if (m.matches()) 
                  return client.get().uri(m.group(1)).exchange();
                
              
              return Flux.empty();
            )
        .flatMap(response -> response.bodyToFlux(GithubUsersResponse.class))
        .flatMap(parsedResponse -> Flux.fromIterable(parsedResponse.getItems()))
        .log();
    

  private Mono<ClientResponse> fetchUsers(Function<UriBuilder, URI> url) 
    return client.get().uri(url).exchange();
  

我可以看到第二页的正则表达式有效,因为如果我在 if 中添加打印,它会被打印,但是如果我在浏览器或邮递员上测试它,我只会得到第一页的结果由github的api返回:

"login":"chrisbanes","id":"227486"
"login":"keyboardsurfer","id":"336005"
"login":"lucasr","id":"730395"
"login":"hitherejoe","id":"3879281"
"login":"Stylingandroid","id":"933874"
"login":"rstoyanchev","id":"401908"
"login":"RichardWarburton","id":"328174"
"login":"slightfoot","id":"906564"
"login":"tomwhite","id":"85085"
"login":"jstrachan","id":"30140"
"login":"wakaleo","id":"55986"
"login":"cesarferreira","id":"277426"
"login":"kevalpatel2106","id":"20060162"
"login":"jodastephen","id":"213212"
"login":"caveofprogramming","id":"19751656"
"login":"AlmasB","id":"3594742"
"login":"scottyab","id":"404105"
"login":"makovkastar","id":"1076309"
"login":"salaboy","id":"271966"
"login":"blundell","id":"655860"
"login":"PierfrancescoSoffritti","id":"7457011"
"login":"0xddr","id":"4354177"
"login":"irsdl","id":"1798313"
"login":"andreban","id":"1733592"
"login":"TWiStErRob","id":"2906988"
"login":"geometer","id":"344328"
"login":"neomatrix369","id":"1570917"
"login":"nebraslabs","id":"32421477"
"login":"lucko","id":"8352868"
"login":"isabelcosta","id":"11148726"

【问题讨论】:

fetchUsers 的实现在哪里,递归展开展平对象projectreactor.io/docs/core/release/api/reactor/core/publisher/… 我不确定这是你想要在那里做的。 @ThomasAndolf 我用缺失的方法编辑了问题 @ThomasAndolf 这是我正在使用的扩展,但正如我所说,它不会获取第二页 【参考方案1】:

Github API 中的 link 标头以转义格式提供 URI。你传递给client.get().uri() 的字符串应该是非转义的 - 所以它会转义转义的字符串,你最终会得到一个什么都不返回的 URL。

相反,您可能想要使用类似于:

if (m.matches()) 
    return client.get().uri(URI.create(m.group(1))).exchange();

旁注 - 您的正则表达式可能还需要在“下一个”链接之前考虑任意数量的字符,否则您将无法越过第二页,因此您可能需要在前面加上 .*那:

Pattern p = Pattern.compile(".*<(.*)>; rel=\"next\".*");

第二个注意事项 - Github 的 API 受到速率限制(如果您未经身份验证,则速率受到严重限制),因此您很可能会遇到这些速率限制。您可能希望以某种方式优雅地处理这种情况,但这是一个相当大的话题,超出了本问题的范围。

【讨论】:

以上是关于WebFlux 扩展未检索第二个请求的主要内容,如果未能解决你的问题,请参考以下文章

在 Spring Boot WebFlux 上检索路径变量(功能方法)

如何在 webflux 中实现自定义身份验证管理器时对未经授权的请求响应自定义 json 正文

spring-boot-webflux 中未使用配置的 ObjectMapper

在 webflux 中读取请求正文

webFlux 学习

Spring webflux请求回调不起作用