Skip to content

Add support for application/x-www-form-urlencoded content type in HTTP Interface (HttpExchange) #35083

Closed as not planned
@salvationFPS

Description

@salvationFPS

Hello!

Summary

Please add support for sending application/x-www-form-urlencoded request bodies using the @HttpExchange / @PostExchange abstraction.

Currently, it is not possible to annotate a method argument which is POJO in an @HttpExchange interface to send form-encoded data in the request body.


Example

@HttpExchange("/token") interface AuthClient { @PostExchange(contentType = MediaType.APPLICATION_FORM_URLENCODED_VALUE) fun getToken( @RequestBody form: MyForm ): TokenResponse }
data class MyForm( val login: String, val password: String, }
authClient.getToken( MyForm("login", "pwd") }

This code leads to org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'application/x-www-form-urlencoded' not supported for bodyType=MyForm


Currently to avoid limitations we can use custom org.springframework.http.codec.HttpMessageWriter

class FormUrlencodedWriter : HttpMessageWriter<Any> { private val supportedMediaType = MediaType.APPLICATION_FORM_URLENCODED override fun canWrite(elementType: ResolvableType, mediaType: MediaType?): Boolean { return supportedMediaType == mediaType } override fun getWritableMediaTypes(): MutableList<MediaType> { return mutableListOf(supportedMediaType) } override fun write( inputStream: Publisher<out Any>, elementType: ResolvableType, mediaType: MediaType?, message: ReactiveHttpOutputMessage, hints: MutableMap<String, Any> ): Mono<Void> { return Flux.from(inputStream).next().flatMap { value -> val form = LinkedMultiValueMap<String, String>() value.javaClass.declaredFields.forEach { field: Field -> field.isAccessible = true val fieldValue = field.get(value) if (fieldValue != null) { val annotation = field.getDeclaredAnnotation(FormProperty::class.java) if (annotation != null) { form.add(annotation.name, fieldValue.toString()) } else { form.add(field.name, fieldValue.toString()) } } } val encoded = UriComponentsBuilder.newInstance() .queryParams(form) .build() .toUri() .rawQuery val bytes = encoded.toByteArray(UTF_8) message.headers.contentType = supportedMediaType message.headers.contentLength = bytes.size.toLong() message.writeWith(Mono.just(message.bufferFactory().wrap(bytes))) } } }

and add it to WebClient

@Bean fun exchangeStrategies(): ExchangeStrategies = ExchangeStrategies.builder() .codecs { config -> config.customCodecs().register(FormUrlencodedWriter()) } .build() @Bean fun webClient(exchangeStrategies: ExchangeStrategies): WebClient = WebClient.builder() .exchangeStrategies(exchangeStrategies) .baseUrl("http://localhost:8081") .build()

I understand that if use org.springframework.util.MultiValueMap as @RequestBody type then everything works fine but POJO support might be good enhancement

This request is similar to https://github.com/OpenFeign/feign-form/ which design was nice

Metadata

Metadata

Assignees

No one assigned

    Labels

    in: webIssues in web modules (web, webmvc, webflux, websocket)status: duplicateA duplicate of another issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions