RestTemplate源码debug:可变形参引发的问题

今天在做一个跨域请求的时候遇到一个问题,我需要同时从JDK7版本的项目接口中取出设置的请求头和响应的二进制流数据,按着源码分析了半天,把API倒是玩明白了,最后发现是因为没有注意可变形参引发的问题。。因为之前没有用过这个API,所以出这个问题的时候也没往这方面想。。。记录一下吧

1.环境模拟

1.1接口提供

提供一个接口,设置一个请求头给response,把图片二进制流写入response

@GetMapping("/pic1")
public void getPic(HttpServletRequest request,HttpServletResponse response) throws IOException {
    response.setHeader("keyy","valuee");
    System.out.println(response.getHeader("keyy"));
    File file = new File("C:\\Users\\zhangjiahao\\Desktop\\变更图片\\班级活动.jpg");
    FileInputStream fis = new FileInputStream(file);
    BufferedInputStream bis = new BufferedInputStream(fis);
    byte[] buf = new byte[2048];
    ServletOutputStream os = response.getOutputStream();
    BufferedOutputStream bos = new BufferedOutputStream(os);
    while(bis.read(buf) != -1){
        bos.write(buf);
    }
    bos.flush();
    bos.close();
    bis.close();
  }

1.2工具类(2个)

前提须知:

  • getForEntity() exchange()本质上都是调用的excute()
    返回值都是ResponseEntity
    产生的问题是,这个ResponseEntity最后在getBody()的时候,一个能读取到二进制流,一个读取不到

1.2.1使用getForEntity()

public static String getStreamAndHeader(String url,String headKey,HttpServletResponse response) {
    RestTemplate restTemplate = getSingleRestTemplate();
    ResponseEntity<byte[]> responseEntity = restTemplate.getForEntity(url, null, byte[].class, (Object) null);

    byte[] res = responseEntity.getBody();//获取不到。res=null
    HttpHeaders headers = responseEntity.getHeaders();
    String      value   = headers.getFirst(headKey);
    try {
        ServletOutputStream os = response.getOutputStream();
        os.write(res);
        os.flush();
        os.close();
    }
    catch (IOException e) {
        logger.error("请求接口二进制流写入response时异常{}",e);
    }

    return value;

}

1.2.2使用exchange()

public static void getStreamWithNoParam(String url, HttpMethod method, HttpServletResponse response) {
    RestTemplate restTemplate = getSingleRestTemplate();
    try {
        ResponseEntity<byte[]> exchange = restTemplate.exchange(url, method, null, byte[].class, (Object) null);


        byte[]                 body     = exchange.getBody();//正常获取
        String value = exchange.getHeaders().getFirst("keyy");
        response.setHeader("keyy",value);
        response.getOutputStream().write(body);
    }
    catch (IOException e) {
        logger.error("RestTemplateUtils获取接口二进制流异常");
    }
}

2.源码分析思路

2.1方法本身区别

调用exchange()的时候,内部调用的方法是需要携带请求参数的,不过可以设为null

getForEntity
exchange
两个方法本身的区别就是:requestEntity,即请求参数

2.2分别看两个内部的方法

2.2.1 exchange-带参的:httpEntityCallback

到目前为止没有看到对返回值response进行操作的内容

2.2.2getFroEntity-无参:acceptHeaderRequestCallback


3.到此没有分析出异常,则看request回调相关的execute

3.1分析理由

因为两个方法的区别就是在于回调RequestCallback,本身分析不出来问题,就去找其他RequestCallback相关的即execute()执行方法本身

3.2doExecute()

doWithRequest()对于这两个方法来说,其实都是会执行的


debug的时候能正常进去

虽然这里没有指定requestEntity

但是内部造了一个requestCallBack,和requestEntity没有关系

4.定位到doWithRequest()

这两个实现类其实是父子类关系,都会调用(内部用的super)两个实现类

4.1 debug 发现支持的媒体类型

发现在使用getForEntity()的时候,走到这里是false,因此没有指定返回值的类型

而正常正确的应该是这样

4.2回去看参数是否正确

发现这里给responseType指定为了null,那么问题来了,为什么参数写错了但是没提示?


这是因为最后最后一个形参是Object... uriVariables,这种形参放在最后一位就支持这种很多逗号的写法

5.修改参数

然后就跑通了

6.结论

其实这两个方法本质只有“是否携带请求参数”的区别,其他的所有东西都一样,执行的过程一样,返回值一样,返回值的使用方式一样。
唯一值得需要注意的是,以后遇到这种最后一个形参是Object... uriVariables的,就要对形参的个数比较敏感一点

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值