I have tried below code to process the request with contentType as "application/x-www-form-urlencoded".
@RequestMapping(value = "/abcd", consumes = {"application/x-www-form-urlencoded"})
public ResponseEntity handleRequest( RequestEntity<String> reqEntity,@RequestParam Map<String, String> params, @RequestHeader HttpHeaders httpHeaders) {
logger.info("Request params received - " + params);
logger.info("Request httpHeaders received - " + httpHeaders);
return new ResponseEntity<>("{\"working\": \"Well\"}", HttpStatus.CREATED);
}
But I am seeing below error
{
"timestamp": "2022-08-03T10:28:35.801+00:00",
"path": "/abcd",
"status": 415,
"error": "Unsupported Media Type",
"message": null,
"requestId": "492dfe63-192"
}
Comment From: wilkinsona
Thanks for the report, @jayapratha1. Without knowing exactly what request you sent, it's impossible for us to tell if things are working correctly. If you would like us to spend some more time investigating, please spend some time providing a complete yet minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.
Comment From: jayapratha1
I tried below request curl --location --request POST 'http://ip:port/abcd' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-raw ''
Comment From: wilkinsona
A request like that works for me. As I said above, if you would like us to spend some more time investigating, please spend some time providing a complete yet minimal sample that reproduces the problem
Comment From: jayapratha1
Hi @wilkinsona
Above mentioned sample code is enough to reproduce the problem for me. I think the request is not able to map the request entity object. If I remove the request entity from the method, then the code works fine with request param and HTTP headers. I want to know why the request is not working with request entity object. I have attached the logs.
SpringBoot Version: "2.6.7" Logs:
{"instant":{"epochSecond":1659541713,"nanoOfSecond":822091293},"thread":"epollEventLoopGroup-2-1","level":"TRACE","loggerName":"org.springframework.web.server.adapter.HttpWebHandlerAdapter","message":"[f45dc198-34] HTTP POST \"/abcd\", headers={masked}","endOfBatch":false,"loggerFqcn":"org.apache.commons.logging.LogAdapter$Log4jLog","threadId":105,"threadPriority":10}
{"instant":{"epochSecond":1659541713,"nanoOfSecond":822832032},"thread":"epollEventLoopGroup-2-1","level":"TRACE","loggerName":"org.springframework.beans.factory.support.DefaultListableBeanFactory","message":"Returning cached instance of singleton bean 'Rocontroller'","endOfBatch":false,"loggerFqcn":"org.apache.commons.logging.LogAdapter$Log4jLog","threadId":105,"threadPriority":10}
{"instant":{"epochSecond":1659541713,"nanoOfSecond":822948071},"thread":"epollEventLoopGroup-2-1","level":"DEBUG","loggerName":"org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping","message":"[f45dc198-34] Mapped to com.sample.rorestcontroller.Rocontroller#handleRequest(RequestEntity, Map, HttpHeaders)","endOfBatch":false,"loggerFqcn":"org.apache.commons.logging.LogAdapter$Log4jLog","threadId":105,"threadPriority":10}
{"instant":{"epochSecond":1659541713,"nanoOfSecond":823235906},"thread":"epollEventLoopGroup-2-1","level":"DEBUG","loggerName":"org.springframework.web.reactive.result.method.annotation.HttpEntityMethodArgumentResolver","message":"Form data is accessed via ServerWebExchange.getFormData() in WebFlux.","endOfBatch":false,"loggerFqcn":"org.apache.commons.logging.LogAdapter$Log4jLog","threadId":105,"threadPriority":10}
{"instant":{"epochSecond":1659541713,"nanoOfSecond":823606815},"thread":"epollEventLoopGroup-2-1","level":"DEBUG","loggerName":"org.springframework.web.method.HandlerMethod","message":"[f45dc198-34] Could not resolve parameter [0] in public org.springframework.http.ResponseEntity com.sample.rorestcontroller.Rocontroller.handleRequest(org.springframework.http.RequestEntity<java.lang.String>,java.util.Map<java.lang.String, java.lang.String>,org.springframework.http.HttpHeaders): 415 UNSUPPORTED_MEDIA_TYPE","endOfBatch":false,"loggerFqcn":"org.apache.commons.logging.LogAdapter$Log4jLog","threadId":105,"threadPriority":10}
{"instant":{"epochSecond":1659541713,"nanoOfSecond":824214546},"thread":"epollEventLoopGroup-2-1","level":"TRACE","loggerName":"org.springframework.web.reactive.function.server.RouterFunctions","message":"[f45dc198-34] Matched org.springframework.web.reactive.function.server.RequestPredicates$$Lambda$1917/0x000000080192ef90@542741d7","endOfBatch":false,"loggerFqcn":"org.apache.commons.logging.LogAdapter$Log4jLog","threadId":105,"threadPriority":10}
{"instant":{"epochSecond":1659541713,"nanoOfSecond":828847296},"thread":"epollEventLoopGroup-2-1","level":"WARN","loggerName":"io.netty.util.concurrent.DefaultPromise","message":"An exception was thrown by reactor.netty.http.server.HttpTrafficHandler.operationComplete()","thrown":{"message":"reactor.left.h2cUpgradeHandler","name":"java.util.NoSuchElementException","extendedStackTrace":[{"class":"io.netty.channel.DefaultChannelPipeline","method":"getContextOrDie","file":"DefaultChannelPipeline.java","line":1073},{"class":"io.netty.channel.DefaultChannelPipeline","method":"addBefore","file":"DefaultChannelPipeline.java","line":248},{"class":"io.netty.channel.DefaultChannelPipeline","method":"addBefore","file":"DefaultChannelPipeline.java","line":237},{"class":"reactor.netty.http.server.HttpTrafficHandler$IdleTimeoutHandler","method":"addIdleTimeoutHandler","file":"HttpTrafficHandler.java","line":511},{"class":"reactor.netty.http.server.HttpTrafficHandler","method":"operationComplete","file":"HttpTrafficHandler.java","line":424},{"class":"reactor.netty.http.server.HttpTrafficHandler","method":"operationComplete","file":"HttpTrafficHandler.java","line":67},{"class":"io.netty.util.concurrent.DefaultPromise","method":"notifyListener0","file":"DefaultPromise.java","line":578},{"class":"io.netty.util.concurrent.DefaultPromise","method":"notifyListenersNow","file":"DefaultPromise.java","line":552},{"class":"io.netty.util.concurrent.DefaultPromise","method":"notifyListeners","file":"DefaultPromise.java","line":491},{"class":"io.netty.util.concurrent.DefaultPromise","method":"setValue0","file":"DefaultPromise.java","line":616},{"class":"io.netty.util.concurrent.DefaultPromise","method":"setSuccess0","file":"DefaultPromise.java","line":605},{"class":"io.netty.util.concurrent.DefaultPromise","method":"trySuccess","file":"DefaultPromise.java","line":104},{"class":"io.netty.util.concurrent.PromiseCombiner","method":"tryPromise","file":"PromiseCombiner.java","line":170},{"class":"io.netty.util.concurrent.PromiseCombiner","method":"access$600","file":"PromiseCombiner.java","line":35},{"class":"io.netty.util.concurrent.PromiseCombiner$1","method":"operationComplete0","file":"PromiseCombiner.java","line":62},{"class":"io.netty.util.concurrent.PromiseCombiner$1","method":"operationComplete","file":"PromiseCombiner.java","line":44},{"class":"io.netty.util.concurrent.DefaultPromise","method":"notifyListener0","file":"DefaultPromise.java","line":578},{"class":"io.netty.util.concurrent.DefaultPromise","method":"notifyListenersNow","file":"DefaultPromise.java","line":552},{"class":"io.netty.util.concurrent.DefaultPromise","method":"notifyListeners","file":"DefaultPromise.java","line":491},{"class":"io.netty.util.concurrent.DefaultPromise","method":"setValue0","file":"DefaultPromise.java","line":616},{"class":"io.netty.util.concurrent.DefaultPromise","method":"setSuccess0","file":"DefaultPromise.java","line":605},{"class":"io.netty.util.concurrent.DefaultPromise","method":"trySuccess","file":"DefaultPromise.java","line":104},{"class":"io.netty.util.internal.PromiseNotificationUtil","method":"trySuccess","file":"PromiseNotificationUtil.java","line":48},{"class":"io.netty.channel.ChannelOutboundBuffer","method":"safeSuccess","file":"ChannelOutboundBuffer.java","line":717},{"class":"io.netty.channel.ChannelOutboundBuffer","method":"remove","file":"ChannelOutboundBuffer.java","line":272},{"class":"io.netty.channel.ChannelOutboundBuffer","method":"removeBytes","file":"ChannelOutboundBuffer.java","line":352},{"class":"io.netty.channel.epoll.AbstractEpollStreamChannel","method":"writeBytesMultiple","file":"AbstractEpollStreamChannel.java","line":305},{"class":"io.netty.channel.epoll.AbstractEpollStreamChannel","method":"doWriteMultiple","file":"AbstractEpollStreamChannel.java","line":510},{"class":"io.netty.channel.epoll.AbstractEpollStreamChannel","method":"doWrite","file":"AbstractEpollStreamChannel.java","line":422},{"class":"io.netty.channel.AbstractChannel$AbstractUnsafe","method":"flush0","file":"AbstractChannel.java","line":931},{"class":"io.netty.channel.epoll.AbstractEpollChannel$AbstractEpollUnsafe","method":"flush0","file":"AbstractEpollChannel.java","line":557},{"class":"io.netty.channel.AbstractChannel$AbstractUnsafe","method":"flush","file":"AbstractChannel.java","line":895},{"class":"io.netty.channel.DefaultChannelPipeline$HeadContext","method":"flush","file":"DefaultChannelPipeline.java","line":1372},{"class":"io.netty.channel.AbstractChannelHandlerContext","method":"invokeFlush0","file":"AbstractChannelHandlerContext.java","line":750},{"class":"io.netty.channel.AbstractChannelHandlerContext","method":"invokeFlush","file":"AbstractChannelHandlerContext.java","line":742},{"class":"io.netty.channel.AbstractChannelHandlerContext","method":"flush","file":"AbstractChannelHandlerContext.java","line":728},{"class":"io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext","method":"flush","file":"CombinedChannelDuplexHandler.java","line":531},{"class":"io.netty.channel.ChannelOutboundHandlerAdapter","method":"flush","file":"ChannelOutboundHandlerAdapter.java","line":125},{"class":"io.netty.channel.CombinedChannelDuplexHandler","method":"flush","file":"CombinedChannelDuplexHandler.java","line":356},{"class":"io.netty.channel.AbstractChannelHandlerContext","method":"invokeFlush0","file":"AbstractChannelHandlerContext.java","line":750},{"class":"io.netty.channel.AbstractChannelHandlerContext","method":"invokeFlush","file":"AbstractChannelHandlerContext.java","line":742},{"class":"io.netty.channel.AbstractChannelHandlerContext","method":"flush","file":"AbstractChannelHandlerContext.java","line":728},{"class":"io.netty.channel.ChannelDuplexHandler","method":"flush","file":"ChannelDuplexHandler.java","line":127},{"class":"io.netty.channel.AbstractChannelHandlerContext","method":"invokeFlush0","file":"AbstractChannelHandlerContext.java","line":750},{"class":"io.netty.channel.AbstractChannelHandlerContext","method":"invokeWriteAndFlush","file":"AbstractChannelHandlerContext.java","line":765},{"class":"io.netty.channel.AbstractChannelHandlerContext","method":"write","file":"AbstractChannelHandlerContext.java","line":790},{"class":"io.netty.channel.AbstractChannelHandlerContext","method":"writeAndFlush","file":"AbstractChannelHandlerConte
{"instant":{"epochSecond":1659541713,"nanoOfSecond":829841756},"thread":"epollEventLoopGroup-2-1","level":"TRACE","loggerName":"org.springframework.web.server.adapter.HttpWebHandlerAdapter","message":"[f45dc198-34] Completed 415 UNSUPPORTED_MEDIA_TYPE, headers={masked}","endOfBatch":false,"loggerFqcn":"org.apache.commons.logging.LogAdapter$Log4jLog","threadId":105,"threadPriority":10}
Comment From: wilkinsona
The logs show that you're using Netty which you hadn't mentioned previously. There may be other things too. I'm afraid I don't have time to guess what those things may be. If you want us to spend any more time on this, please provide a complete yet minimal sample, otherwise we will have to close this issue.
Comment From: jayapratha1
hi @wilkinsona
I updated the sample project demo 2.zip
Comment From: wilkinsona
Thanks. I can now reproduce the behavior that you have described. You shouldn't be using a MultiValueMap method argument to access form data in WebFlux. Instead, you should use ServerWebExchange.getFormData() as suggested in the logging that your sample produces:
Aug 09, 2022 2:25:44 PM org.springframework.web.reactive.result.method.annotation.AbstractMessageReaderArgumentResolver readBody
FINE: Form data is accessed via ServerWebExchange.getFormData() in WebFlux.
Alternatively, you can use data binding to bind the form to a POJO.
If you have any further questions, please follow up on Stack Overflow or Gitter. As mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements.