使用@FeignClient调用微服务时出现Method Not Allowed错误求助
问题:FeignClient跨服务调用出现Method Not Allowed错误
项目包含三个微服务:Hotel Service、Hotel-rating Service、User-service。通过User-Service调用Hotel-Service时触发错误:"Method Not Allowed while using @FeignClient",依赖为Spring Cloud Eureka client/server、FeignClient。
User Controller代码
@GetMapping("/{userId}") public ResponseEntity<?> getUser(@PathVariable("userId") String userId) { User user = this.userService.getUser(userId); return new ResponseEntity<>(user, HttpStatus.OK); }
UserServiceImpl代码
@Override public User getUser(String userId) { User user = this.userRepo.findById(userId).orElseThrow(() -> new ResourceNotFounds("user id not found " + userId)); ResponseEntity<List<Rating>> ratingByUser = this.hotelRating.getRatingByUser(user.getId());// 使用FeignClient List<Rating> ratings = ratingByUser.getBody(); user.setRatings(ratings); // 从Hotel服务获取酒店信息 List<Rating> collect = ratings.stream().map(userH -> { logger.info("Hotel Id "+ userH.getHotelId()); ResponseEntity<Hotel> hotelResponse = hotelService.getHotel(userH.getHotelId()); logger.info("status code ", hotelResponse.getStatusCode()); Hotel hotel = hotelResponse.getBody(); // 为User对象设置Hotel对象 userH.setHotel(hotel); return userH; }).collect(Collectors.toList()); return user; }
HotelService(UserService中FeignClient接口)
@Service @FeignClient(name = "HOTEL-SERVICE") public interface HotelService { // @GetMapping("/hotel/{hotelId}") // Hotel getHotel(@PathVariable("hotelId") String hotelId); @RequestMapping(method = RequestMethod.GET, value = "/hotel/{hotelId}") ResponseEntity<Hotel> getHotel(@PathVariable("hotelId") String hotelId); // 获取所有酒店信息 @GetMapping("/hotel/all") ResponseEntity<List<Hotel>> getAllHotelList(); }
HotelController(被调用的Hotel服务接口)
@GetMapping("/{hotelId}") public ResponseEntity<Hotel> getHotel(@PathVariable("hotelId") String hotelId){ Hotel hotel = this.hotelService.getHotel(hotelId); return new ResponseEntity<>(hotel , HttpStatus.OK); }
错误信息
feign.FeignException$MethodNotAllowed: [405] during [GET] to [http://HOTEL-SERVICE/hotel/] [HotelService#getHotel(String)]: [{"timestamp":"2023-02-26T16:21:16.604+00:00","status":405,"error":"Method Not Allowed","path":"/hotel/"}] at feign.FeignException.clientErrorStatus(FeignException.java:221) ~[feign-core-11.10.jar:na] at feign.FeignException.errorStatus(FeignException.java:194) ~[feign-core-11.10.jar:na] at feign.FeignException.errorStatus(FeignException.java:185) ~[feign-core-11.10.jar:na]
测试环境正常情况
@Autowired private HotelService hotelService; @Test void getSingleHotelInfor(){ ResponseEntity<Hotel> hotel = this.hotelService.getHotel("72db342b-678c-486b-8d37-25b97851cec6"); System.out.println(hotel.getBody().getName()); }
解决方案
1. 对齐HotelController的请求前缀
从错误信息可见,Feign实际请求路径为/hotel/(未携带hotelId),核心问题是Feign接口定义的路径与Hotel服务实际接口路径不匹配:
- Feign接口中定义的路径是
/hotel/{hotelId} - 当前HotelController的方法仅配置了
@GetMapping("/{hotelId}"),若Controller类无@RequestMapping("/hotel")前缀,实际接口路径应为/{hotelId},与Feign定义的路径不符。
修复方式:给HotelController类添加路径前缀,确保路径匹配:
@RequestMapping("/hotel") @RestController public class HotelController { @GetMapping("/{hotelId}") public ResponseEntity<Hotel> getHotel(@PathVariable("hotelId") String hotelId){ Hotel hotel = this.hotelService.getHotel(hotelId); return new ResponseEntity<>(hotel , HttpStatus.OK); } }
2. 过滤无效的hotelId数据
测试环境正常但业务调用出错,大概率是从Hotel-rating Service获取的ratings列表中存在空/空白的hotelId:
当userH.getHotelId()为空时,Feign会生成/hotel/的请求路径,而Hotel服务未定义该路径的GET接口,导致405错误。
修复方式:在代码中添加空值过滤逻辑:
// 过滤掉hotelId为空的rating数据 List<Rating> collect = ratings.stream() .filter(rating -> rating.getHotelId() != null && !rating.getHotelId().trim().isEmpty()) .map(userH -> { logger.info("Hotel Id "+ userH.getHotelId()); ResponseEntity<Hotel> hotelResponse = hotelService.getHotel(userH.getHotelId()); logger.info("status code ", hotelResponse.getStatusCode()); Hotel hotel = hotelResponse.getBody(); userH.setHotel(hotel); return userH; }).collect(Collectors.toList());
3. 简化FeignClient接口定义
将Feign接口中的@RequestMapping替换为更简洁的@GetMapping,避免配置冗余:
@FeignClient(name = "HOTEL-SERVICE") public interface HotelService { @GetMapping("/hotel/{hotelId}") ResponseEntity<Hotel> getHotel(@PathVariable("hotelId") String hotelId); @GetMapping("/hotel/all") ResponseEntity<List<Hotel>> getAllHotelList(); }
内容的提问来源于stack exchange,提问作者Jitendra
相关产品推荐
相关产品推荐

