Http Post Request With Content Type Application/X-Www-Form-Urlencoded Not Working in Spring

How to post request with spring boot web-client for Form data for content type application/x-www-form-urlencoded

We can use BodyInserters.fromFormData for this purpose

webClient client = WebClient.builder()
.baseUrl("SOME-BASE-URL")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
.build();

return client.post()
.uri("SOME-URI)
.body(BodyInserters.fromFormData("username", "SOME-USERNAME")
.with("password", "SONE-PASSWORD"))
.retrieve()
.bodyToFlux(SomeClass.class)
.onErrorMap(e -> new MyException("messahe",e))
.blockLast();

Spring Boot - Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported

As @Sunil Dabburi suggests debugging the readWithMessageConverters method in the AbstractMessageConverterMethodArgumentResolver sheds light on this issue, which turns out to be pretty simple once understood. Spring has about 15 default message converters, which are responsible for converting the content of an incoming request to a RequestEntity or HttpEntity. If the request has body, the converter reads it and converts it to the object type it is responsible for. Depending on the incoming request's Media Type, each converter decides whether it can read the request. In the case of the application/x-www-form-urlencoded Media Type none of the default Spring converters can process such a request. Therefore, the above mentioned error occurs.

Adding a custom converter for the application/x-www-form-urlencoded Media Type to the list of Spring's http message converters would solve the issue. In the example below the custom converter is responsible only for reading requests and only for requests with the desired Media Type.

** These reads help understanding the media type itself and how does spring work with it, thus how should the custom converter convert the incoming request:

  • About the media type
  • Default Spring handling and why does it work with MultiValueMap as only parameter
  • The needed request body object type (MultiValueMap<String, String>) for Spring to create RequestEntity/HttpEntity for this media type

Here is an example of such custom http message converter:

@Component
public class FormUrlencodedHttpMessageConverter extends
AbstractGenericHttpMessageConverter<MultiValueMap<String, String>> {

private static final MediaType CONVERTER_MEDIA_TYPE = MediaType.APPLICATION_FORM_URLENCODED;

public FormUrlencodedHttpMessageConverter() {
super(CONVERTER_MEDIA_TYPE);
}

@Override
public MultiValueMap<String, String> read(Type type, Class<?> contextClass, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {

String urlEncodedData = new BufferedReader(
new InputStreamReader(inputMessage.getBody(), StandardCharsets.UTF_8)).readLine();

String[] keyValuePairs = urlEncodedData.split("&");
MultiValueMap<String, String> keyValuePairsMap = new LinkedMultiValueMap<>();

for (String keyValuePair : keyValuePairs) {
String[] pairElements = keyValuePair.split("=");
String key = pairElements[0];
String value = pairElements[1];
keyValuePairsMap.add(key, value);
}

return keyValuePairsMap;
}

@Override
protected boolean canRead(@Nullable MediaType mediaType) {

return CONVERTER_MEDIA_TYPE.includes(mediaType);
}

@Override
protected boolean canWrite(@Nullable MediaType mediaType) {

return CONVERTER_MEDIA_TYPE.includes(mediaType);
}

@Override
protected void writeInternal(MultiValueMap<String, String> t, Type type, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
throw new RuntimeException("Method 'writeInternal' in " + this.getClass().getSimpleName() + " is not implemented");
}

@Override
protected MultiValueMap<String, String> readInternal(Class<? extends MultiValueMap<String, String>> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
throw new RuntimeException("Method 'readInternal' in " + this.getClass().getSimpleName() + " is not implemented");
}


Related Topics



Leave a reply



Submit