Spring/Eureka/Feign - FeignClient setting Content-Type header to application/x-www-form-urlencoded
The answer was to do as @spencergibb suggests; use the consumes
directive in the @RequestMapping
annotation on the FeignClient
interface. This Spring/Netflix documentaition also has an example.
So for example the @FeignClient
interface declaration in the client is now:
@FeignClient("alarm-service")
public interface AlarmFeignService {
@RequestMapping(method = RequestMethod.POST, value = "/site/alarm", consumes = "application/json"))
RaiseAlarmResponseDto raiseAlarm(RaiseSiteAlarmRequestDto requestDto);
}
Note this is only necessary on the client side and the server side controller does not need to have this change.
Would be nice if this was done by default on the @FeignClient
and then it would be the consistent with RestTemplate
and the server side controller @RequestMapping
annotation. Maybe that can be done in a future release of spring-cloud
.
user1232555
Updated on July 05, 2022Comments
-
user1232555 almost 2 years
When I use a
FeignClient
it is setting theContent-Type
toapplication/x-www-form-urlencoded
instead ofapplication/json;charset=UTF-8
.If I use a
RestTemplate
to send the same message the message headerContent-Type
is correctly set toapplication/json;charset=UTF-8
.Both the
FeignClient
andRestTemplate
are usingEureka
for service discovery, and I discovered this problem by debugging the HTTP message received by the server.The controller on the server side looks like this:
@RestController @RequestMapping("/site/alarm") public class SiteAlarmController { @RequestMapping(method = RequestMethod.POST) @ResponseBody public ResponseEntity<RaiseAlarmResponseDto> raiseAlarm(@RequestBody RaiseSiteAlarmRequestDto requestDto) { ... }
My
FeignClient
interface in the service that calls the alarm looks like this:@FeignClient("alarm-service") public interface AlarmFeignService { @RequestMapping(method = RequestMethod.POST, value = "/site/alarm") RaiseAlarmResponseDto raiseAlarm(@RequestBody RaiseSiteAlarmRequestDto requestDto); }
The HTTP message headers from the
FeignClient
are:Accept: */* Cache-Control: no-cache Pragma: no-cache User-Agent: Java/1.7.0_60 Host: smit005s-MacBook-Pro.local:9120 Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 323
The alarm service doesn't like the
Content-Type
and throws the following exception:2015-04-22 12:12:28.580 thread="qtp1774842986-25" class="org.eclipse.jetty.servlet.ServletHandler" level="WARN" org.springframework.web.util.NestedServletException: Request processing failed; nested exception is feign.FeignException: status 415 reading AlarmFeignService#raiseAlarm(RaiseSiteAlarmRequestDto); content: {"timestamp":1429701148576,"status":415,"error":"Unsupported Media Type","exception":"org.springframework.web.HttpMediaTypeNotSupportedException","message":"Unsupported Media Type","path":"/site/alarm"} at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978) ~[spring-webmvc-4.1.5.RELEASE.jar:4.1.5.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857) ~[spring-webmvc-4.1.5.RELEASE.jar:4.1.5.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:618) ~[tomcat-embed-core-8.0.20.jar:8.0.20] ... ... /* commented rest of stack out */ ...
If I change the client side code to use a
RestTemplate
as follows:@Service public class AlarmService { @Autowired private RestTemplate restTemplate; ... public void send(RaiseSiteAlarmRequestDto alarm) { RaiseAlarmResponseDto result = restTemplate.postForObject("http://alarm-service/site/alarm", raiseSiteAlarmRequestDto, RaiseAlarmResponseDto.class); } }
It works with the
RestTemplate
, thealarm-service
receives the message and processes it successfully. The message headers sent by theRestTemplate
are:Accept: application/json, application/*+json Content-Type: application/json;charset=UTF-8 Cache-Control: no-cache Pragma: no-cache User-Agent: Java/1.7.0_60 Host: smit005s-MacBook-Pro.local:9120 Connection: keep-alive Content-Length: 323
-
jebeaudet about 9 yearsHave you tried ditching the
ResponseEntity<T>
of your controller to test if this was interfering with the Feign Client? My other guess is that Feign is not able to deserialize yourRaiseAlarmResponseDto
object. -
spencergibb about 9 yearsThe
@RequestBody
on the@FeignClient
doesn't do anything. Can you make a successful call without feign, but with eureka? -
user1232555 about 9 yearsThanks @spencergibb that was a good suggestion. Changing it to a RestTemplate does work, and it is discovering the service through Eureka. When I put debugging on the receiver side I can see the the feign client is sending it with the
Content-Type
header set incorrectly toapplication/x-www-form-urlencoded
. While theRestTemplate
sets theContent-Type
toapplication/json;charset=UTF-8
. I will update the question with this. -
spencergibb about 9 yearsHave you tried adding
consumes="application/json"
to the@RequestMapping
on the@FeignClient
? -
user1232555 about 9 yearsYes that works. But from the examples I've seen that should be unnecessary.
-
user1232555 about 9 yearsHi @spencergib with a simple change I can recreate this on a feign example project of yours on githib. So should I raise a bug against spring-cloud for this? In meantime we can progress by using the consumes and produces directives as you suggested.
-
spencergibb about 9 years@user1232555 yes, raise an issue, reference this stack overflow question and tell us how you can recreate this.
-
burcakulug about 8 yearshi, i think this issue is still going on, is it planned to be fixed in the future?
-
-
Jorge Machado almost 7 yearsIt does not work for application/x-www-form-urlencoded you will get : feign.codec.EncodeException: Could not write request: no suitable HttpMessageConverter found for request type [com.*.pojos.OAuthLoginPojo] and content type [application/x-www-form-urlencoded]
-
Dan Brandt over 4 yearsadding custom converter doesn't work for me too