OpenFeign 开发随笔

常见错误

Request method ‘POST’ not supported

  • 错误信息:在调用 OpenFeign 下面这段代码时,抛出了 Request method 'POST' not supported 的异常
1
2
3
4
5
6
7
8
9
10
/**
* 服务调用方
*/
@FeignClient(name = MicroServiceName.WECHAT_SERVICE)
public interface WechatSubscribeUserService {

@RequestMapping(value = "/wechat/subscribe/get", method = RequestMethod.GET)
WechatSubscribeUser getSubscribeUser(@RequestBody WechatSubscribeUserVo vo);

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 服务提供方
*/
@RestController
@RequestMapping("/wechat/subscribe")
public class WechatSubscribeUserController {

@Autowired
private WechatSubscribeUserService subscribeUserService;

@GetMapping("/get")
public WechatSubscribeUser get(WechatSubscribeUserVo vo) {
String toOpenId = vo.getToOpenId();
String fromOpenId = vo.getFromOpenId();
return subscribeUserService.getUser(fromOpenId, toOpenId);
}

}
  • 错误原因:OpenFeign 原生的连接工具默认使用了 JDK 中的 HttpURLConnection 类进行实现,下面这段代码是在 HttpURLConnection 中发现的,所以只要 HTTP 请求里有 Body 体对象,就会强制的把 GET 请求转换成 POST 请求。
1
2
3
4
5
6
7
8
9
10
11
private synchronized OutputStream getOutputStream0() throws IOException {
try {
if (!this.doOutput) {
throw new ProtocolException("cannot write to a URLConnection if doOutput=false - call setDoOutput(true)");
} else {
if (this.method.equals("GET")) {
this.method = "POST";
}
}
}
}
  • 第一种解决方案:不使用 POJO 对象作为参数,而是传入多个独立的参数,并添加 @RequestParam 注解
1
2
3
4
5
6
7
8
9
10
/**
* 服务调用方
*/
@FeignClient(name = MicroServiceName.WECHAT_SERVICE)
public interface WechatSubscribeUserService {

@RequestMapping(value = "/wechat/subscribe/get", method = RequestMethod.GET)
WechatSubscribeUser getSubscribeUser(@RequestParam("fromOpenId") String fromOpenId, @RequestParam("toOpenId") String toOpenId);

}
  • 第二种解决方案:使用 POJO 对象作为参数,同时添加 @SpringQueryMap 注解
1
2
3
4
5
6
7
8
9
10
/**
* 服务调用方
*/
@FeignClient(name = MicroServiceName.WECHAT_SERVICE)
public interface WechatSubscribeUserService {

@RequestMapping(value = "/wechat/subscribe/get", method = RequestMethod.GET)
WechatSubscribeUser get(@SpringQueryMap WechatSubscribeUserVo vo);

}

提示

Feign 的 @QueryMap 注解支持将 POJO 用作 GET 请求的参数映射,但默认的 @QueryMap 注解与 Spring 不兼容,因为它缺少 value 属性。Spring Cloud OpenFeign 提供了等效的 @SpringQueryMap 注解,用于将 POJO 或 Map 参数映射为查询参数。简而言之,Feign 的 GET 请求无法解析对象参数,如果传参是一个类对象,框架就需要把这个类对象解析成查询参数,但是直接在方法中传参框架不会自动把类对象解析成查询参数。@SpringQueryMap 注解的作用就是把 POJO 解析成 k1=v1&k2=v2 的查询参数格式。

  • 第三种解决方案:使用 Apache HttpClient 或者 OkHttp 替换掉 OpenFeign 原生使用的 HttpURLConnection 连接工具,然后添加 @RequestBody 注解
1
2
3
4
5
6
7
8
9
10
/**
* 服务调用方
*/
@FeignClient(name = MicroServiceName.WECHAT_SERVICE)
public interface WechatSubscribeUserService {

@RequestMapping(value = "/wechat/subscribe/get", method = RequestMethod.GET)
WechatSubscribeUser getSubscribeUser(@RequestBody WechatSubscribeUserVo vo);

}

warning

笔者尝试使用 Apache HttpClient 或者 OkHttp 替换 OpenFeign 默认使用的 HttpURLConnection,但并没有生效,有兴趣的可以参考这里的 替换教程