WebFlux 扩展未检索第二个请求
WebFlux expand is not retrieving the second request
我正在尝试使用 Spring 的 webflux 创建一个 http 端点来流式传输 github 使用 Github 的 api 的用户。我尝试按照 and 中描述的进行操作,但似乎扩展没有从 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"}
Github API 中的 link
header 以转义格式提供 URI。你传递给 client.get().uri()
的字符串应该是未转义的——所以它转义了转义的字符串,你最终得到一个 URL 而 returns 什么都没有。
相反,您可能想使用类似于以下内容的内容:
if (m.matches()) {
return client.get().uri(URI.create(m.group(1))).exchange();
}
旁注 - 您的正则表达式可能需要考虑 "next" link 之前的任意数量的字符,否则您将无法通过第二页,因此您可能想在前面加上 .*
:
Pattern p = Pattern.compile(".*<(.*)>; rel=\"next\".*");
第二个旁注 - Github 的 API 有速率限制(如果您未经身份验证,则会受到严重速率限制),因此您很可能 运行 进入这些速率限制。您可能希望以某种方式优雅地处理这种情况,但这是一个相当大的话题,超出了这个问题的范围。
我正在尝试使用 Spring 的 webflux 创建一个 http 端点来流式传输 github 使用 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"}
Github API 中的 link
header 以转义格式提供 URI。你传递给 client.get().uri()
的字符串应该是未转义的——所以它转义了转义的字符串,你最终得到一个 URL 而 returns 什么都没有。
相反,您可能想使用类似于以下内容的内容:
if (m.matches()) {
return client.get().uri(URI.create(m.group(1))).exchange();
}
旁注 - 您的正则表达式可能需要考虑 "next" link 之前的任意数量的字符,否则您将无法通过第二页,因此您可能想在前面加上 .*
:
Pattern p = Pattern.compile(".*<(.*)>; rel=\"next\".*");
第二个旁注 - Github 的 API 有速率限制(如果您未经身份验证,则会受到严重速率限制),因此您很可能 运行 进入这些速率限制。您可能希望以某种方式优雅地处理这种情况,但这是一个相当大的话题,超出了这个问题的范围。