Feign访问外部http请求
大家好,目前接手了一个项目,具体的逻辑并不复杂,主要是一个"中间商"角色, 比如客户端通过我访问高德地图API,就不需要带秘钥,直接带高德API所需的入参和url后缀,就可以访问。
目前遇到这样一个问题,项目架构师要求所有的项目自己写的htttpClintUtils或者其他工具,需要替换到feign的形式来完成调用,但是,目前这个项目访问外部的http接口很多,比如,提供的高德服务就有10多种,一共有大几十类型,这样的话,如果按照以前的方式,一个接口指定一个高德子服务,那岂不是要累死 = =!
累死人的写法:(仅参考)
@FeignClient(value = "test",url = "http://ip:port")
public interface TestFeign {
@PostMapping(value = "/Amap/geo")
Object geo(@RequestBody GeoEntity entity);
@PostMapping(value = "/Amap/regeo")
Object regeo(@RequestBody RegeoEntity entity);
.........
...........
}
然后如果我除了高德服务还有其他外部服务,并且其他外部服务下的子接口,不一定就两个,那这样写的话,要头大死,并且这样的写法,在服务的内部,不能做秘钥和权限的动态配置,只能在url上做指定,比较笨拙,所以就需要一种可以灵活访问外部httpClient的Feign接口,只需要我指定一个url,指定下提交的post数据,就可以得到返回结果,岂不是美滋滋?
话不多说,先上pom.xml
<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 部分配置
feign:
httpclient:
enabled: true
hystrix:
enabled: true
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000 #降级超时时间,我设置为3秒。 feign.retry默认超时时间是5s.
设置了个降级超时时间,还有启动了feign访问外部httpClient配置和服务降级配置。
在spingbootApplication启动类上增加注解
@EnableFeignClients
@EnableHystrix
代码部分:
public interface HttpRequestFeign {
@RequestLine("GET")
String sendGetRequest(URI baseUri);
@RequestLine("POST")
String sendPostRequest(URI baseUri, Map map);
}
调用部分,这里我在我的BaseController构造注解,其他服务Controller继承,提供调用能力:
@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注解,并指定降级方法:
@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
<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
@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参数
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;
@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);
}
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。