Spring/Eureka/Feign - FeignClient setting Content-Type header to application/x-www-form-urlencoded

32,034

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.

Share:
32,034
user1232555
Author by

user1232555

Updated on July 05, 2022

Comments

  • user1232555
    user1232555 almost 2 years

    When I use a FeignClient it is setting the Content-Type to application/x-www-form-urlencoded instead of application/json;charset=UTF-8.

    If I use a RestTemplate to send the same message the message header Content-Type is correctly set to application/json;charset=UTF-8.

    Both the FeignClient and RestTemplate are using Eureka 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, the alarm-service receives the message and processes it successfully. The message headers sent by the RestTemplate 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
      jebeaudet about 9 years
      Have 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 your RaiseAlarmResponseDto object.
    • spencergibb
      spencergibb about 9 years
      The @RequestBody on the @FeignClient doesn't do anything. Can you make a successful call without feign, but with eureka?
    • user1232555
      user1232555 about 9 years
      Thanks @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 to application/x-www-form-urlencoded. While the RestTemplate sets the Content-Type to application/json;charset=UTF-8. I will update the question with this.
    • spencergibb
      spencergibb about 9 years
      Have you tried adding consumes="application/json" to the @RequestMapping on the @FeignClient?
    • user1232555
      user1232555 about 9 years
      Yes that works. But from the examples I've seen that should be unnecessary.
    • user1232555
      user1232555 about 9 years
      Hi @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
      spencergibb about 9 years
      @user1232555 yes, raise an issue, reference this stack overflow question and tell us how you can recreate this.
    • burcakulug
      burcakulug about 8 years
      hi, i think this issue is still going on, is it planned to be fixed in the future?
  • Jorge Machado
    Jorge Machado almost 7 years
    It 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
    Dan Brandt over 4 years
    adding custom converter doesn't work for me too