Spring WebFlux, как я могу отладить обмен сообщениями WebClient?
у меня возникли проблемы с пониманием того, что я сделал неправильно при построении моего запроса WebClient. Я хотел бы понять, как выглядит фактический HTTP-запрос. (например, сброс необработанного запроса на консоль)
POST /rest/json/send HTTP/1.1
Host: emailapi.dynect.net
Cache-Control: no-cache
Postman-Token: 93e70432-2566-7627-6e08-e2bcf8d1ffcd
Content-Type: application/x-www-form-urlencoded
apikey=ABC123XYZ&from=example%40example.com&to=customer1%40domain.com&to=customer2%40domain.com&to=customer3%40domain.com&subject=New+Sale+Coming+Friday&bodytext=You+will+love+this+sale.
Я использую реактивные инструменты Spring5 для создания API. У меня есть класс утилиты, который отправит электронное письмо с помощью api электронной почты Dyn. Я хотел бы использовать новый класс WebClient для этого (org.springframework.сеть.реактивный.функция.клиент.WebClient)
следующая команда была взята из:https://help.dyn.com/email-rest-methods-api/sending-api/#postsend
curl --request POST "https://emailapi.dynect.net/rest/json/send" --data "apikey=ABC123XYZ&from=example@example.com&to=customer1@domain.com&to=customer2@domain.com&to=customer3@domain.com&subject=New Sale Coming Friday&bodytext=You will love this sale."
когда я делаю вызов в curl с реальными значениями, электронная почта отправляет правильно, поэтому я чувствую, что генерирую свой запрос неправильно.
Отправка Команды
public Mono<String> send( DynEmailOptions options )
{
WebClient webClient = WebClient.create();
HttpHeaders headers = new HttpHeaders();
// this line causes unsupported content type exception :(
// headers.setContentType( MediaType.APPLICATION_FORM_URLENCODED );
Mono<String> result = webClient.post()
.uri( "https://emailapi.dynect.net/rest/json/send" )
.headers( headers )
.accept( MediaType.APPLICATION_JSON )
.body( BodyInserters.fromObject( options ) )
.exchange()
.flatMap( clientResponse -> clientResponse.bodyToMono( String.class ) );
return result;
}
Мой Класс DynEmailOptions
import java.util.Collections;
import java.util.Set;
public class DynEmailOptions
{
public String getApikey()
{
return apiKey_;
}
public Set<String> getTo()
{
return Collections.unmodifiableSet( to_ );
}
public String getFrom()
{
return from_;
}
public String getSubject()
{
return subject_;
}
public String getBodytext()
{
return bodytext_;
}
protected DynEmailOptions(
String apiKey,
Set<String> to,
String from,
String subject,
String bodytext
)
{
apiKey_ = apiKey;
to_ = to;
from_ = from;
subject_ = subject;
bodytext_ = bodytext;
}
private Set<String> to_;
private String from_;
private String subject_;
private String bodytext_;
private String apiKey_;
}
2 ответов
в настоящее время вы пытаетесь сериализовать тело запроса "как есть", не используя right BodyInserter
.
в этом случае, я думаю, что вы должны превратить ваш DynEmailOptions
объект в MultiValueMap<String, String>
и затем:
MultiValueMap<String, String> formData = ...
Mono<String> result = webClient.post()
.uri( "https://emailapi.dynect.net/rest/json/send" )
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.accept( MediaType.APPLICATION_JSON )
.body( BodyInserters.fromFormData(formData))
.retrieve().bodyToMono(String.class);
вопрос заключается в отладке WebClient POST. Я нашел большую помощь в callicoder.com.
ключ должен добавить фильтр в WebClient. Фильтр обеспечивает легкий доступ как к запросам, так и к ответам. Для обоих запросов и ответов вы можете получить доступ к методу, URL, заголовкам и другим вещам. Однако вы не можете получить доступ к телу. Надеюсь, я ошибаюсь, но на самом деле существует только метод body() для установки тела.
здесь я должен жаловаться на странные поведение WebClient POST. Иногда, вместо того, чтобы получить ответ 4XX сразу, он блокирует навсегда. Иногда он дает 501 ответ. Мой совет: попробуйте использовать LinkedMultiValueMap для переноса тела, Избегайте использования простой строки или java.утиль.Карта.
вот мой пример кода, используя GitHub V3 API в качестве примера:
@Bean
public WebClient client() {
return WebClient.builder()
.baseUrl("https://api.github.com")
.defaultHeader("User-Agent", "Spring-boot WebClient")
.filter(ExchangeFilterFunctions.basicAuthentication("YOUR_GITHUB_USERNAME", "YOUR_GITHUB_TOKEN"))
.filter(printlnFilter).build();
}
ExchangeFilterFunction printlnFilter= new ExchangeFilterFunction() {
@Override
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
System.out.println("\n\n" + request.method().toString().toUpperCase() + ":\n\nURL:"
+ request.url().toString() + ":\n\nHeaders:" + request.headers().toString() + "\n\nAttributes:"
+ request.attributes() + "\n\n");
return next.exchange(request);
}
};
//In some method:
String returnedJSON = client.post().uri(builder->builder.path("/user/repos").build())
.contentType(MediaType.APPLICATION_JSON)
.syncBody(new LinkedMultiValueMap<String, String>(){{
put("name", "tett");
}})
.retrieve()
.bodyToMono(String.class)
.block(Duration.ofSeconds(3))
вы увидите такие вещи, как:
2018-04-07 12:15:57.823 INFO 15448 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8084
2018-04-07 12:15:57.828 INFO 15448 --- [ main] c.e.w.WebclientDemoApplication : Started WebclientDemoApplication in 3.892 seconds (JVM running for 8.426)
POST:
URL:https://api.github.com/user/repos:
Headers:{Content-Type=[application/json], User-Agent=[Spring-boot WebClient], Authorization=[Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX]}
Attributes:{}
есть 2 вещи, о которых нужно помнить:
1. Последовательность фильтров имеет значение. Поменять местами эти 2 фильтра и заголовок аутентификации не будет включен.
2. Фильтры фактически применяются ко всем запросам через этот экземпляр WebClient.
https://www.callicoder.com/spring-5-reactive-webclient-webtestclient-examples/ каждый полезно, может быть, вы должны прочитать его и скачать его пример кода.