Spring/Eureka/Feign - FeignClient设置Content-Type标题到application/x-www-form-urlencoded

use*_*555 1 spring-boot spring-cloud netflix-feign netflix-eureka

当我使用FeignClient它时,它设置Content-Typeapplication/x-www-form-urlencoded而不是application/json;charset=UTF-8.

如果我使用a RestTemplate发送相同的消息,则消息头Content-Type正确设置为application/json;charset=UTF-8.

无论是FeignClientRestTemplate正在使用Eureka的服务发现,并通过我调试服务器接收HTTP消息发现了这个问题.

服务器端的控制器如下所示:

@RestController
@RequestMapping("/site/alarm")
public class SiteAlarmController {
    @RequestMapping(method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<RaiseAlarmResponseDto> raiseAlarm(@RequestBody RaiseSiteAlarmRequestDto requestDto) {
        ...
    }
Run Code Online (Sandbox Code Playgroud)

FeignClient在电话报警的服务接口看起来是这样的:

@FeignClient("alarm-service")
public interface AlarmFeignService {
    @RequestMapping(method = RequestMethod.POST, value = "/site/alarm")
    RaiseAlarmResponseDto raiseAlarm(@RequestBody RaiseSiteAlarmRequestDto requestDto);
}
Run Code Online (Sandbox Code Playgroud)

来自的HTTP消息头FeignClient是:

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
Run Code Online (Sandbox Code Playgroud)

警报服务不喜欢Content-Type和抛出以下异常:

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 */
    ...
Run Code Online (Sandbox Code Playgroud)

如果我更改客户端代码使用RestTemplate如下:

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

它适用于RestTemplate,alarm-service接收消息并成功处理它.发送的邮件标题RestTemplate是:

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
Run Code Online (Sandbox Code Playgroud)

use*_*555 11

答案就像@spencergibb建议的那样; 在接口consumes@RequestMapping注释中使用该指令FeignClient.这个Spring/Netflix文档也有一个例子.

例如,@FeignClient客户端中的接口声明现在是:

@FeignClient("alarm-service")
public interface AlarmFeignService {
    @RequestMapping(method = RequestMethod.POST, value = "/site/alarm", consumes = "application/json"))
    RaiseAlarmResponseDto raiseAlarm(RaiseSiteAlarmRequestDto requestDto);
}
Run Code Online (Sandbox Code Playgroud)

请注意,这仅在客户端需要,服务器端控制器不需要进行此更改.

如果这是默认情况下完成@FeignClient然后它将与RestTemplate服务器端控制器@RequestMapping注释一致将是很好的.也许这可以在将来的版本中完成spring-cloud.