通过FeignClient如何获取文件流steam is close问题

目录
  • FeignClient获取文件流 steam is close问题
    • 原因
    • 解决办法
  • FeignClient注解参数
    • 日志级别配置
    • 服务超时、重试、降级和熔断

FeignClient获取文件流 steam is close问题

inputstream.read 报错 steam is close

原因

idea debug启动导致

解决办法

直接启动

FeignClient注解参数

  • name:指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现
  • url: url一般用于调试,可以手动指定@FeignClient调用的地址
  • decode404:当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException
  • configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract
  • fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口
  • fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码
  • path: 定义当前FeignClient的统一前缀

日志级别配置

默认Feign是不打印任何日志的,下面我们来开启Feign的日志,Feign有四种日志级别:

  • NONE【性能最佳,适用于生产】:不记录任何日志(默认值)。
  • BASIC【适用于生产环境追踪问题】:仅记录请求方法、URL、响应状态代码以及执行时间。
  • HEADERS:记录BASIC级别的基础上,记录请求和响应的header。
  • FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的header、body和元数据。

在application.yml 中添加以下内容,将该Feign接口的日志级别设置为DEBUG:

# 定义feign客户端所在的路径,需要设置日志级别为debug
logging.level: com.example.customer.service.CustomerService: debug
# user为服务名,单个配置客户端日志级别设置,如果需要全局配置,把user更换为default
feign.client.config.user.loggerLevel: FULL

调用日志信息截图

2020-06-07 14:06:27.671 DEBUG 24961 --- [nio-8081-exec-3] c.e.customer.service.CustomerService     : [CustomerService#getUser] ---> GET http://user/user HTTP/1.1
2020-06-07 14:06:27.671 DEBUG 24961 --- [nio-8081-exec-3] c.e.customer.service.CustomerService     : [CustomerService#getUser] ---> END HTTP (0-byte body)
2020-06-07 14:06:27.678 DEBUG 24961 --- [nio-8081-exec-3] c.e.customer.service.CustomerService     : [CustomerService#getUser] <--- HTTP/1.1 200  (7ms)
2020-06-07 14:06:27.679 DEBUG 24961 --- [nio-8081-exec-3] c.e.customer.service.CustomerService     : [CustomerService#getUser] connection: keep-alive
2020-06-07 14:06:27.679 DEBUG 24961 --- [nio-8081-exec-3] c.e.customer.service.CustomerService     : [CustomerService#getUser] content-type: application/json
2020-06-07 14:06:27.679 DEBUG 24961 --- [nio-8081-exec-3] c.e.customer.service.CustomerService     : [CustomerService#getUser] date: Sun, 07 Jun 2020 06:06:27 GMT
2020-06-07 14:06:27.679 DEBUG 24961 --- [nio-8081-exec-3] c.e.customer.service.CustomerService     : [CustomerService#getUser] keep-alive: timeout=60
2020-06-07 14:06:27.679 DEBUG 24961 --- [nio-8081-exec-3] c.e.customer.service.CustomerService     : [CustomerService#getUser] transfer-encoding: chunked
2020-06-07 14:06:27.679 DEBUG 24961 --- [nio-8081-exec-3] c.e.customer.service.CustomerService     : [CustomerService#getUser]
2020-06-07 14:06:27.679 DEBUG 24961 --- [nio-8081-exec-3] c.e.customer.service.CustomerService     : [CustomerService#getUser] {"id":1,"name":"test","phone":"119"}
2020-06-07 14:06:27.679 DEBUG 24961 --- [nio-8081-exec-3] c.e.customer.service.CustomerService     : [CustomerService#getUser] <--- END HTTP (36-byte body)

服务超时、重试、降级和熔断

·超时 Feign接口调用分两层,Ribbon(负载均衡)和Hystrix(熔断器)的调用,因此Feign的超时时间就是ribbon的超时时间和Hystrix的超时时间的结合

·重试 使用Ribbon

设置Ribbon重试次数

ribbon:
  #连接超时时间
  ConnectTimeout: 1000
  #读超时时间
  ReadTimeout: 1000
  ##同一台实例最大重试次数,不包括首次调用
  MaxAutoRetries: 0
  #重试负载均衡其他的实例最大重试次数,不包括首次调用
  MaxAutoRetriesNextServer: 1
  #是否所有操作都重试,设置false时,只会对get请求进行重试;如果设置为true,便会对所有的请求进行重试,如果是put或post等写操作,如果服务器接口没做幂等性,慎用;
  OkToRetryOnAllOperations: false

负载均衡配置

#服务名
user:
  ribbon:
    #选择随机算法
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

Ribbon Eager加载

默认情况下Ribbon是懒加载的——首次请求Ribbon相关类才会初始化,这会导致首次请求过慢的问题,你可以配置饥饿加载,让Ribbon在应用启动时就初始化。

ribbon:
  eager-load:
    enabled: true
    # 多个用,分隔
    clients: user

降级和熔断使用hystrix

如果重试期间,调用时间超过了 Hystrix熔断的超时时间,便会立即熔断,进行FallBack

# 开启hystrix
feign.hystrix.enabled: true
# hystrix的超时时间 时间设置需要根据实际业务场景计算得出
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 10000

Fallback配置

@FeignClient(name = "user", fallback = CustomerFeignClientFallback.class)
public interface CustomerService {

  /**
   * 获取用户信息
   *
   * @return 用户信息
   */
  @GetMapping("/user")
  UserDTO getUser ();

  @Component
  public class CustomerFeignClientFallback implements CustomerService {

    @Override
    public UserDTO getUser () {
     //todo 回退逻辑
      return new UserDTO().setName("服务降级");
    }
  }
}
@FeignClient(name = "user", fallbackFactory = CustomerFeignClientFallbackFactory.class)
public interface CustomerService {

  /**
   * 获取用户信息
   *
   * @return 用户信息
   */
  @GetMapping("/user")
  UserDTO getUser ();

  @Component
  @Slf4j
  public class CustomerFeignClientFallbackFactory implements FallbackFactory<CustomerService> {

    @Override
    public CustomerService getUser () {
       //todo 回退逻辑
      return new UserDTO().setName("服务降级");
    }
  }
}

配置

logging:
  level:
    com.example.customer.service.CustomerService: debug
#全局配置,单个服务配置把default替换为需要设置的服务名
feign:
  client.config.default.loggerLevel: FULL
  okhttp.enabled: true
  #熔断与回退
  hystrix.enabled: true
#重试机制
ribbon:
  #连接超时时间
  ConnectTimeout: 2000
  #读超时时间
  ReadTimeout: 2000
  ##同一台实例最大重试次数,不包括首次调用
  MaxAutoRetries: 0
  #重试负载均衡其他的实例最大重试次数,不包括首次调用
  MaxAutoRetriesNextServer: 1
  #是否所有操作都重试
  OkToRetryOnAllOperations: false
# Hystrix的超时时间
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 10000

有关Feign超时时间易混淆概念

Feign超时时间

feign.client.config.default.connectTimeout=10000 //Feign的连接建立超时时间,默认为10秒
feign.client.config.default.readTimeout=60000 //Feign的请求处理超时时间,默认为60

Ribbon 超时时间

ribbon.ReadTimeout=1000 //处理请求的超时时间,默认为1秒
ribbon.ConnectTimeout=1000 //连接建立的超时时长,默认1秒

Hystrix 超时时间

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000 #熔断器的超时时长默认1秒

以上各种超时配置,如果都存在,则时间小的配置生效

小提示

  • Feign的底层是调用ribbon来实现负载均衡的,为了不和ribbon的重试机制冲突不需要配置feign超时时间和重试功能,只需配置ribbon和hystrix超时时间即可。
  • Ribbon超时时间必须小于hysrix超时设置,这样才能触发ribbon重试,ribbon重试分为两种情况,同一实例重试和负载均衡的不同实例重试,默认为1次和0次
  • Feign的默认配置,是不启用hystrix,需要开启feign.hystrix.enabled=true,这样hystrix的相关配置才可以在Feign中生效。
  • Hystrix的超时时间=Ribbon的重试次数(包含首次) * (ribbon.ReadTimeout + ribbon.ConnectTimeout)
  • Ribbon超时但Hystrix没有超时的情况下,Ribbon便会采取重试机制;而重试期间如果时间超过了Hystrix的超时配置则会立即被熔断(fallback)
  • 关系图

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

(0)

相关推荐

  • Spring Cloud Feign接口返回流的实现

    服务提供者 @GetMapping("/{id}") public void queryJobInfoLogDetail(@PathVariable("id") Long id, HttpServletResponse response) { File file = new File("xxxxx"); InputStream fileInputStream = new FileInputStream(file); OutputStream ou

  • 自定义feignClient的常见坑及解决

    目录 自定义feignClient的常见坑 一.从eureka上拉取相关服务的配置信息 二.feignClient 发送请求到目标服务器 三.一些坑 四 .以下是现有全部的代码粘贴出来看一下 feignClient的使用 服务提供端代码 服务调用端 自定义feignClient的常见坑 自定义feignClient 踩过的坑,因为spring cloud 需要spring 4 以上的版本,所以对于低版本工程想要使用feign就需要自定义,在定义过程中遇到了很多问题,整理总结一下.(有需要的结合g

  • 解决feignClient调用时获取返回对象类型匹配的问题

    feignClient调用时获取返回对象类型匹配 feignClient是springCloud体系中重要的一个组件,用于微服务之间的相互调用,底层为httpClient,在之前的应用中,我一直以为A服务提供的方法返回类型为对象的话,那么调用A服务的B服务必须也用字段类型以及命名完全相同的对象来接收,为此我验证了一下,发现不是必须用完全相同的对象来接收,比如,可以用map<String,Object>或者Object来接收,然后解析. 当然,复杂对象我还是推荐用一个完全相同的对象来接收. 下面

  • 通过FeignClient如何获取文件流steam is close问题

    目录 FeignClient获取文件流 steam is close问题 原因 解决办法 FeignClient注解参数 日志级别配置 服务超时.重试.降级和熔断 FeignClient获取文件流 steam is close问题 inputstream.read 报错 steam is close 原因 idea debug启动导致 解决办法 直接启动 FeignClient注解参数 name:指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服

  • 浅谈图片上传利用request.getInputStream()获取文件流时遇到的问题

    图片上传功能是我们web里面经常用到的,获得的方式也有很多种,这里我用的是request.getInputStream()获取文件流的方式.想要获取文件流有两种方式,附上代码 int length = request.getContentLength();//获取请求参数长度. byte[] bytes = new byte[length];//定义数组,长度为请求参数的长度 DataInputStream dis = new DataInputStream(request.getInputSt

  • springboot如何获取文件流

    目录 springboot获取文件流 前端获取springboot返回的文件流的踩坑 踩过坑的我给您提供一个答案 两种解决方案 springboot获取文件流 在日常开发中,经常会获取项目的相对路径用以获取存放在项目路径下的资源,如获取static/ss.txt 在spring项目中,  可以用request.getRealPath("/")获取项目路径然后拼接起来,再生成流: //拼接地址 String downLoadUrl = request.getRealPath("

  • React获取Java后台文件流并下载Excel文件流程解析

    记录使用blob对象接收java后台文件流并下载为xlsx格式的详细过程,关键部分代码如下. 首先在java后台中设置response中的参数: public void exportExcel(HttpServletResponse response, String fileName, String sheetName, List<String> titleRow, List<List<String>> dataRows) { OutputStream out = nu

  • Java 如何获取url地址文件流

    目录 获取url地址文件流 根据url获取文件的二进制 上代码 获取url地址文件流 /** * 根据url下载文件流 * @param urlStr * @return */ public static InputStream getInputStreamFromUrl(String urlStr) { InputStream inputStream=null; try { //url解码 URL url = new URL(java.net.URLDecoder.decode(urlStr,

  • JAVA读取文件流,设置浏览器下载或直接预览操作

    最近项目需要在浏览器中通过URL预览图片.但发现浏览器始终默认下载,而不是预览.研究了一下,发现了问题: // 设置response的Header,注意这句,如果开启,默认浏览器会进行下载操作,如果注释掉,浏览器会默认预览. response.addHeader("Content-Disposition", "attachment;filename=" + FileUtil.getOriginalFilename(path)); 然后需要注意: response.s

  • C#远程获取图片文件流的方法

    本文实例讲述了C#远程获取图片文件流的方法.分享给大家供大家参考,具体如下: protected void Page_Load(object sender, EventArgs e) { WebRequest myrequest = WebRequest.Create("http://xxxxx/userface.jpg"); WebResponse myresponse = myrequest.GetResponse(); Stream imgstream = myresponse.

  • 详解Java如何获取文件编码格式

    1:简单判断是UTF-8或不是UTF-8,因为一般除了UTF-8之外就是GBK,所以就设置默认为GBK. 按照给定的字符集存储文件时,在文件的最开头的三个字节中就有可能存储着编码信息,所以,基本的原理就是只要读出文件前三个字节,判定这些字节的值,就可以得知其编码的格式.其实,如果项目运行的平台就是中文操作系统,如果这些文本文件在项目内产生,即开发人员可以控制文本的编码格式,只要判定两种常见的编码就可以了:GBK和UTF-8.由于中文Windows默认的编码是GBK,所以一般只要判定UTF-8编码

  • HttpsURLConnection上传文件流(实例讲解)

    项目需要对接外部接口,将图片文件流发送到外部接口,下面代码就是HttpsURLConnection如何上传文件流: /** * HttpsURLConnection上传文件流 * * @param args * @throws Exception */ public static void main(String[] args) throws Exception { //本地图片 java.io.File file = new java.io.File("/Users/jikukalun/Pic

  • PHP接收App端发送文件流的方法

    本文实例讲述了PHP接收App端发送文件流的方法.分享给大家供大家参考,具体如下: 解决思路: 1. 客户端多张图片进行循环上传,同时附带参数,并用一定规则组合生产数据流(图片数据放在最后) 2. 使用数据流进行传输,php服务端用file_get_content('php://input')进行接收 3. 传输完毕后将数据流按照规则分割,取出最后的图片数据,并写入图片文件 示例代码: 以下代码是发送单张图片和参数PHP文件,多张图片可循环调用. <?php /* curl_post.php *

随机推荐