Ограничить размер HTTP-ответа на Spring WebFlux
Я пишу http crawler, используя Spring WebFlux, и его легко выполнять параллельно и иметь таймауты HTTP:
val sitesToCrawl: Flux<String> = streamOfUrl()
val concurrencyLimit = 100
sitesToCrawl.flatMap(
{ WebClient.create().get().uri(it).exchange().timeout(Duration.ofSeconds(10)) },
concurrencyLimit
)
Но как я могу ограничить размер ответа страницы, как будто я не хочу загружать более 500 КБ данных для каждого URL. Чтение HTTP-заголовка Content-Length не является надежным. Я думаю, мне нужно перейти на один уровень вниз и напрямую использовать байтовые буферы и события Netty, но было бы неплохо обернуть это, используя Flux/Mono, чтобы продолжать использовать эти примитивы.
1 ответ
Если вы используете Spring Boot, вы должны создать свой WebClient
используя автоматически настроенный WebClient.Builder
; это будет отражать мнение Spring Boot и, например, будет настраивать декодирование Джексона в соответствии с выбранными вами параметрами конфигурации.
Вы также должны создать один и использовать его для многих запросов, вместо того, чтобы создавать новый экземпляр клиента для каждого запроса - это неэффективно.
Теперь, начиная с Spring Framework 5.1 (Spring Boot 2.1), Spring WebFlux поставляется с функцией фильтра, которая делает именно это: она читает N байтов, а затем отменяет ответ (прекращает чтение и закрывает соединение). Обратите внимание, что это поведение интересно, если ответ довольно большой, но это также сделает соединение непригодным для повторного использования и не будет возвращено в пул соединений. Если вы сканируете много страниц на одном хосте, пул соединений против создания новых соединений является интересным компромиссом.
Теперь это должно выглядеть так:
@Component
public class CrawlingService {
private WebClient webClient;
public CrawlingService(WebClient.Builder builder) {
this.webClient = builder.filter(ExchangeFilterFunctions.limitResponseSize(maxSize))
.build();
}
public Mono<Void> crawlPage(URI page) {
return // use webClient here
}
}
Если вы не готовы использовать Spring Boot 2.1 (он еще не выпущен), вы всегда можете посмотреть на реализацию функции фильтра и скопировать / вставить этот код в ваш проект, это очень мало.