填坑系列之OpenFeign(一)


前提

使用OpenFeign構建微服務消費端,發送帶參請求時,控制台報錯:

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is feign.FeignException$InternalServerError: [500 ] during [GET] to [http://user-provider/user/isConsumerId] [UserConsumerService#isID(Integer)]: [{"timestamp":"2020-12-10T06:44:07.262+00:00","status":500,"error":"Internal Server Error","message":"","path":"/user/isConsumerId"}]] with root cause

方法

spring-cloud-openfeign-core 3.0.0版本以及舊版本中,必須在consumer的api需要傳的參數前添加@RequestParam(“paramName”)(當然也可使用@PathVariable("id"),使用這個注解時,需要在consumer的controller層、api都要使用@PathVariable("id"),才能接收到參數,或者使用@RequestBody),參數名不可省略。

實例

以三個服務,分別為user-apiuser-provideruser-consumer,這里將api抽取出來,好處是可以將api打包發給用戶,而且寫起來也挺爽的...0.0。壞處是損失了平台異構性,即必須要java實現的平台才能調,不過也沒啥關系,等有異構的需求時,在寫另外一套就是了,互不干擾。

user-api:

@RequestMapping("/user")
public interface RegisterApi {

    @GetMapping("/isConsumerId")
    String isID(Integer id);
}

user-provider:

@RestController
public class UserController implements RegisterApi {

    @Override
    public String isID(Integer id) {
        return id == 1 ? "success" : "not find";
    }
}

user-consumer:

package com.yiming.user_consumer.service;

@FeignClient(name = "user-provider")
public interface UserConsumerService extends RegisterApi {

    @GetMapping("/isConsumerId")
    String isID(@RequestParam("id") Integer id);
}
package com.yiming.user_consumer.controller;

@RestController
public class ConsumerFindIDController {

    @Autowired
    UserConsumerService consumerService;

    @GetMapping("/findById")
    public String findId(Integer id) {
        return consumerService.isID(id);
    }
}

原因

String isID(@RequestParam("id") Integer id),實際上是交由Feign組裝POST請求 http://user-provider/isConsumerId?id={1},此時@RequestParam("id")是強制要求的,否則報錯。當然使用@PathVariable("id")也可,或者使用@RequestBody。總而言之,如果需要傳參,必須要保證Feign能正確的獲取到相應的參數,才能組裝正確的Http請求。


擴展:

若需動態傳參,可將參數放入map中,如下所示:

user_api:

@RequestMapping("/user")
public interface RegisterApi {

    @GetMapping("/map")
    Map<String, Object> getMap(Map<String, Object> map);
}

user-provider:

@RestController
public class UserController implements RegisterApi {

    @Override
    public Map<String, Object> getMap(@RequestParam Map<String, Object> map) {
        System.out.println(map);
        return Collections.singletonMap(map.get("name").toString(), Integer.parseInt(map.get("age").toString()));
    }
}

user-consumer:

package com.yiming.user_consumer.service;

@FeignClient(name = "user-provider")
public interface UserConsumerService extends RegisterApi {

    @GetMapping("/map")
    Map<String, Object> getMap(@RequestParam Map<String, Object> map);
}
package com.yiming.user_consumer.controller;

@RestController
public class ConsumerFindIDController {

    @Autowired
    UserConsumerService consumerService;

    @GetMapping("/getMap")
    public Map<String, Object> getMap(@RequestParam Map<String, Object> map) {
        return consumerService.getMap(map);
    }
}

后記

稍等,還有一個坑:

由於OpenFeign默認所有帶參數的請求都是POST請求,當發送GET請求時,Feign會將其轉為POST請求。

如果想使用指定的提交方式,需要替換底層實現,替換方法如下:

  1. 導入依賴
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>
  1. 在api中指明提交方式
@RequestMapping(value = "/xxx", method = RequestMethod.GET)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM