好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

SpringCloud如何利用Feign访问外部http请求

Feign访问外部http请求

大家好,目前接手了一个项目,具体的逻辑并不复杂,主要是一个"中间商"角色, 比如客户端通过我访问高德地图API,就不需要带秘钥,直接带高德API所需的入参和url后缀,就可以访问。

目前遇到这样一个问题,项目架构师要求所有的项目自己写的htttpClintUtils或者其他工具,需要替换到feign的形式来完成调用,但是,目前这个项目访问外部的http接口很多,比如,提供的高德服务就有10多种,一共有大几十类型,这样的话,如果按照以前的方式,一个接口指定一个高德子服务,那岂不是要累死 = =!

 累死人的写法:(仅参考)

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

@FeignClient (value = "test" ,url = "http://ip:port" )

public interface TestFeign {

    /**

      * @return 高德服务接口

      * @description 访问高德地理编码服务

      */

    @PostMapping (value = "/Amap/geo" )

    Object geo( @RequestBody GeoEntity entity);

 

    /**

      * @return 高德服务接口

      * @description 访问高德逆地理编码服务

      */

    @PostMapping (value = "/Amap/regeo" )

    Object regeo( @RequestBody RegeoEntity entity);  

    .........

    ...........

}

然后如果我除了高德服务还有其他外部服务,并且其他外部服务下的子接口,不一定就两个,那这样写的话,要头大死,并且这样的写法,在服务的内部,不能做秘钥和权限的动态配置,只能在url上做指定,比较笨拙,所以就需要一种可以灵活访问外部httpClient的Feign接口,只需要我指定一个url,指定下提交的post数据,就可以得到返回结果,岂不是美滋滋?

话不多说,先上pom.xml

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

  < dependency >

            < groupId >org.springframework.cloud</ groupId >

            < artifactId >spring-cloud-starter-openfeign</ artifactId >

            < version >2.0.1.RELEASE</ version >

        </ dependency >

 

        < dependency >

            < groupId >org.springframework.cloud</ groupId >

            < artifactId >spring-cloud-starter-netflix-hystrix</ artifactId >

            < version >2.0.1.RELEASE</ version >

        </ dependency >

 

        <!-- 引入 httpclient -->

        < dependency >

            < groupId >org.apache.httpcomponents</ groupId >

            < artifactId >httpclient</ artifactId >

        </ dependency >

        < dependency >

            < groupId >com.netflix.feign</ groupId >

            < artifactId >feign-httpclient</ artifactId >

            < version >8.18.0</ version >

        </ dependency >

前两个是feign和服务降级用到的包,后两个是用Apache Http替换原生的feign-http-client用来提供连接池等功能。

bootstap.yml 部分配置

?

1

2

3

4

5

6

7

8

9

10

11

12

feign:

   httpclient:

    enabled: true

   hystrix:

    enabled: true

hystrix:

   command:

    default:

      execution:

        isolation:

          thread:

            timeoutInMilliseconds: 3000  #降级超时时间,我设置为3秒。 feign.retry默认超时时间是5s.

设置了个降级超时时间,还有启动了feign访问外部httpClient配置和服务降级配置。

在spingbootApplication启动类上增加注解

@EnableFeignClients   @EnableHystrix

代码部分:

?

1

2

3

4

5

6

7

public interface HttpRequestFeign { 

    @RequestLine ( "GET" )

    String sendGetRequest(URI baseUri);

 

    @RequestLine ( "POST" )

    String sendPostRequest(URI baseUri, Map map);

}

调用部分,这里我在我的BaseController构造注解,其他服务Controller继承,提供调用能力:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

  @Autowired

    public BaseController(Decoder decoder, Encoder encoder) {

        httpRequestFeign = Feign.builder().encoder(encoder).decoder(decoder)

                .target(Target.EmptyTarget.create(HttpRequestFeign. class )); 

    }

  protected String httpPostSend( String url, Map map) {

        String response = "" ;

        try {

            response = httpRequestFeign.sendPostRequest( new URI(url), map);

            logger.info( "调用外部服务返回的数据为->{}" , response);

            // 这里改成重试的超时异常

        } catch (RetryableException a) {

            logger.error( "调用外部服超时错误->{}" , response);

        } catch (Exception e) {

            logger.error( "调用外部服异常错误->{}" , response);

        }

        return response;

    }

这里只列举了Post的,Get方式,就不用了携带map参数了。

然后在你的Controller层增加降级@HystrixCommand注解,并指定降级方法:

?

1

2

3

4

5

6

7

8

9

10

11

  @HystrixCommand(fallbackMethod = "fallback")

  @PostMapping(value = "/1_0_0/{subServer}", produces = "application/json;charset=UTF-8")

  public Object send(@RequestBody Map< String , Object> map, @PathVariable String subServer) {

 

.......................

.................... 

 

  private Object fallback(Map< String , String> map, String subserver, Throwable e) {

        logger.error("xxx服务发生问题,入参:{},地址:{}", map, subserver);

        return Result.fail(ResultCode.INTERNAL_SERVER_ERROR.getCode(), ERROR_MSG + e.toString());

    }

在send方法里可以自行进行拼接url,而Map就是传递给第三方服务的数据。 

FeignClient外部http请求

springboot 4.0.0

pom.xml 引入openfeign 2.0.2

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

< dependencyManagement >

         < dependencies >

             < dependency >

                 < groupId >org.springframework.cloud</ groupId >

                 < artifactId >spring-cloud-openfeign</ artifactId >

                 < version >2.0.2.BUILD-SNAPSHOT</ version >

                 < type >pom</ type >

                 < scope >import</ scope >

             </ dependency >

         </ dependencies >

     </ dependencyManagement >

     < dependencies >

<!--外部http请求 FeignClient-->

         < dependency >

             < groupId >org.springframework.cloud</ groupId >

             < artifactId >spring-cloud-starter-openfeign</ artifactId >

         </ dependency >

</ dependencies >

< repositories >

         <!--外部http请求 FeignClient-->

         < repository >

             < id >spring-snapshots</ id >

             < name >Spring Snapshots</ name >

             < url >https://repo.spring.io/libs-snapshot</ url >

             < snapshots >

                 < enabled >true</ enabled >

             </ snapshots >

         </ repository >

     </ repositories >

启动类 添加注解@EnableFeignClients

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

@SpringBootApplication

@MapperScan ( "com.sichuang.repository.dao" ) //将项目中对应的mapper类的路径加进来就可以了

@ServletComponentScan

@EnableFeignClients

public class RepositoryApplication extends SpringBootServletInitializer{

     public static void main(String[] args) {

         SpringApplication.run(RepositoryApplication. class , args);

     }

     @Override

     protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {

         // TODO Auto-generated method stub

//      return super.configure(builder);

         return builder.sources(RepositoryApplication. class );

     }

}

外部接口类。调用方式同service

@RequestParam 参数注解

produces = MediaType.APPLICATION_JSON_UTF8_VALUE 返回json参数

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

package com.sichuang.repository.api;

import com.alibaba.fastjson.JSON;

import com.alibaba.fastjson.JSONObject;

import org.springframework.cloud.openfeign.FeignClient;

import org.springframework.http.MediaType;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestParam;

import java.util.Map;

/**

  * 对接接口

  *

  * @author xs

  * @date 2018/10/8 9:08

  */

@FeignClient (url = "${url}" , name = "Ewaytec2001API" )

public interface Ewaytec2001API {

    /**

      */

    @GetMapping (value = "${url}" , produces = MediaType.APPLICATION_JSON_UTF8_VALUE)

    String getEmployeeInfo( @RequestParam ( "id" ) int id, @RequestParam ( "sign" ) String sign);

}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://blog.csdn.net/gpdsjqws/article/details/106567397

查看更多关于SpringCloud如何利用Feign访问外部http请求的详细内容...

  阅读:24次