RestTemplate响应中如何获取输入流InputStream

目录
  • RestTemplate调用接口如何获取输入流
  • SpringRestTemplate解析
    • RESTful
    • RestTemplate
    • ​总结

RestTemplate调用接口如何获取输入流

由于项目需求,需要获取RestTemplate请求响应的输入流。如下:

首先需要获取一个RestTemplate实例:

RestTemplate rest = new RestTemplate();

一般的使用方式如下:

String message = rest.getForObject(url, String.class);
// or
String message = rest.postForObject(url, paramObject, String.class);

若要获取InputStream,需要使用到spring提供Resource接口和ResponseEntity类,方式如下:

ResponseEntity<Resource> entity = rest.postForEntity(url, paramObject, Resource.class);
InputStream in = entity.getBody().getInputStream();

当然,我们也可以先使用entity对响应做出判断,比如检查响应状态:

if (entity.getStatusCode().equals(HttpStatus.OK)) {
    // ...
}

SpringRestTemplate解析

RESTful

简单来说,RESTful是基于Http协议,面向资源和语义的设计风格。它可以看做是Http协议的一种严格实现,基于Http资源(URI)和语义(Get/Post/Put/Delete等)

作为对比,PRC则是面向过程(资源+语义),而对协议没有固定要求的设计风格。它的目的是将远程方法当做本地方法一样调用,相比于RESTful的面向资源和语义,它将两者结合起来,作为我们平时开发过程中的方法。

​ 比如一个订单查询系统,用RESTful风格的写法是这样的

// 这里查询用的是Http语义GET,对应的新增为POST,删除为DELETE,修改为PUT
GET
/order/123

用PRC风格的写法是这样的

/order/queryOrder/123

RPC对比

总结来看,RESTful和PRC有以下不同。

​ 1、RESTful基于Http协议,而RPC对协议没有固定要求,一般会采用效率较高的协议。

​ 2、RESTful面向资源和语义,而RPC面向过程。即RESTful提供的资源表达十分明确,提供了多种语义作为资源的操作方法,例如上面的订单查询。RPC则会为同一个资源提供多个操作方法,对外并没有十分明确的资源概念。

RestTemplate

HttpMessageConverter及序列化

​序列化就是将对象转化为可以传输的二进制,反序列化就是将二进制转化为程序内部的对象。序列化/反序列化主要体现在程序I/O这个过程中,包括网络I/O和磁盘I/O。在网络中Http报文是以二进制字符串的形式传递的,这种是反序列化前的存在形式,我们要在Java中处理,则还需要进行反序列化操作。

我们可以通过HttpServletRequest的getInputStream()方法获取请求报文的原始内容,HttpServletResponse的getOutputStream()方法写入响应报文,这些方式都是通过流的形式来处理数据,如果要转化为对象,还需要我们进一步处理。在面向对象的模式中,每次都需要读取流中的原始数据并转化为对象,这样显然是很麻烦的,如果能将请求和响应都自动封装为我们想要的对象,那不是很好嘛。HttpMessageConverter提供的就是这样的功能,将原始的请求报文和响应报文封装为对象。

public interface HttpMessageConverter<T> {
	boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
	boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
	List<MediaType> getSupportedMediaTypes();
	T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
			throws IOException, HttpMessageNotReadableException;
	void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
			throws IOException, HttpMessageNotWritableException;
}

​HttpMessageConverter中出现了成对的read和write方法。每种Converter负责处理其各自支持的MimeType,can**()方法通过判断当前Converter和需要处理的MimeType是否一致,如果一致则能处理,否则不能处理。如果能处理,则再通过read/write()方法进行操作,其本质上也是通过输入输出流处理数据,我们来看下StringHttpMessageConverter是如何将请求报文转化为String对象的:

// 判断当前Converter是否支持此类型的转换,只有是String时才会支持
@Override
public boolean supports(Class<?> clazz) {
	return String.class == clazz;
}

// 从HttpInputMessage读取输入流,并转化为String对象
@Override
protected String readInternal(Class<? extends String> clazz, HttpInputMessage inputMessage) throws IOException {
	Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType());
	return StreamUtils.copyToString(inputMessage.getBody(), charset);
}

// 从InputStream中读取原始的报文数据
public static String copyToString(@Nullable InputStream in, Charset charset) throws IOException {
    if (in == null) {
        return "";
    } else {
        StringBuilder out = new StringBuilder();
        InputStreamReader reader = new InputStreamReader(in, charset);
        char[] buffer = new char[4096];

        int charsRead;
        while((charsRead = reader.read(buffer)) != -1) {
            out.append(buffer, 0, charsRead);
        }

        return out.toString();
    }
}

组件替换

从上面的UML可以看出,RestTemplate中定义了一组Http语义的模板方法,并通过HttpAccessor创建了HttpRequest对象再执行请求。也就是说,RestTemplate中并没有创建请求,请求是委托给HttpAccessor创建的,HttpAccessor可以切换请求工厂,这样就给我们提供了切换请求,即Http组件的操作。

通过HttpAccessor的ClientHttpRequestFactory属性来切换不同的HTTP组件:HttpAccessor默认使用SimpleClientHttpRequestFactory来创建一个ClientHttpRequest,如果通过HttpAccessor提供的setRequestFactory()方法替换掉其默认的工厂,就可以实现HTTP组件切换。RestTemplate提供了以ClientHttpRequestFactory为参数的构造方法,其内部调用了setRequestFactory()。

通过看ClientHttpRequestFactory的实现类,可以发现常见的Http组件有HttpComponents、OkHttp、Netty4Client等,在这里不做深入探究。

​总结

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

(0)

相关推荐

  • RestTemplate调用POST和GET请求示例详解

    目录 正文 一.POST请求调用 二.GET请求调用 三.Exchange调用 正文 在日常开发过程中,http接口不仅提供给前端调用,有的时候还需要提供给其他业务方调用,在后台调用http请求的时候,我们一般使用Http Client客户端调用,java常用的Http客户端有: java原生的HttpURLConnection Apache http client OkHttp RestTemplate 下面来详细介绍一下使用RestTemplate来调用Post和Get请求. 在RestTe

  • RestTemplate Get请求实现bean参数传递详解

    目录 项目场景 问题描述 原因分析 解决方案 项目场景 Spring 的 RestTemplate 是一个健壮的.流行的基于 Java 的 Http客户端. RestTemplate实现request param参数传送,如果如下所示,直接传一个map对象,调试之后是不会接收到参数的 Map<String,Object> param = new HashMap<String,Object>(); param.put("since",10); restTempla

  • 工具类之关于RestTemplateUtil工具类的使用

    目录 工具类-RestTemplateUtil工具类 代码可直接复制使用 RestTemplate配置类和工具类 工具类-RestTemplateUtil工具类 代码可直接复制使用 配置RestTemplate import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http

  • SpringBoot-RestTemplate实现调用第三方API的方式

    RestTemplate简介Spring RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率,所以很多客户端比如 Android或者第三方服务商都是使用 RestTemplate 请求 restful 服务. 下面通过代码讲解下SpringBoot-RestTemplate实现调用第三方API的方法,内容如下所示: 1. RestTemplate的方式来调用别人的AP

  • Java Http请求方式之RestTemplate常用方法详解

    目录 引言 常见用法 简单Get\Post请求 Post提交常规表单 Post上传文件 配置项 请求添加Cookie\Header 配置请求工厂 超时.代理 配置拦截器.转换器,错误处理 错误重试(额外) SSL请求 基于RestTemplate一些工具 钉钉机器人通知 总结 引言 在开发中有时候经常需要一些Http请求,请求数据,下载内容,也有一些简单的分布式应用直接使用Http请求作为跨应用的交互协议. 在Java中有不同的Http请求方式,主要就是HttpURLConnection或者Ap

  • 详解Java中restTemplate的使用

    目录 1 提供get/post接口 1.1 Controller 1.2 Service 2 调用get/post接口 2.1 Controller 2.2 Service 本文介绍restTemplate基础用法. Java中get和post的用法请参考:一文带你搞懂Java中Get和Post的使用 1 提供get/post接口 1.1 Controller @RestController @RequestMapping("/homepage") public class MyCon

  • Spring中如何获取request的方法汇总及其线程安全性分析

    前言 本文将介绍在Spring MVC开发的web系统中,获取request对象的几种方法,并讨论其线程安全性.下面话不多说了,来一起看看详细的介绍吧. 概述 在使用Spring MVC开发Web系统时,经常需要在处理请求时使用request对象,比如获取客户端ip地址.请求的url.header中的属性(如cookie.授权信息).body中的数据等.由于在Spring MVC中,处理请求的Controller.Service等对象都是单例的,因此获取request对象时最需要注意的问题,便是

  • SpringBoot通过请求对象获取输入流无数据

    目录 请求对象获取输入流无数据问题 方案一:禁用默认的过滤器 方案二:使用@RequestBody注解 方案三:自定义HiddenHttpMethodFilter过滤器 request输入流重复可读 自定义类继承 HttpServletRequestWrapper 定义一个过滤器 Filter 创建过滤器配置类 FilterConfig 请求对象获取输入流无数据问题 昨天下午在开发的时候遇到了奇怪的事情,在SpringBoot的Controller里面直接使用HttpServletRequest

  • Python 仅获取响应头, 不获取实体的实例

    Python Just get Response Headers, not get content. 1. Use HEAD method >>> import requests >>> res = requests.head("http://www.baidu.com/") >>> req.head("https://www.baidu.com/").headers {'Content-Encoding': '

  • python3中编码获取网页的实例方法

    学了python后,之前一些我们常用的方法,也可以换一种思路用python中的知识来解决.相信操作出来后,能收获一大批小粉丝们.就像我们没学习编程之前,看到那种大神都是可望而不可即.今天我们就之前简单获取网页的这种操作用python中的编码来解决,大家可以自行体会一下两者的不同. 1. encoding和apparent_encoding import scrapy url="https://www.xxx.net/html/gndy/dyzz/index.html" re=reque

  • Java中Spring获取bean方法小结

    Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架,如何在程序中获取Spring配置的bean呢? Bean工厂(com.springframework.beans.factory.BeanFactory)是Spring框架最核心的接口,它提供了高级IoC的配置机制.BeanFactory使管理不同类型的Java对象成为可能,应用上下文(com.springframework.context.ApplicationContext)建立在BeanFactory基础之上,提供

  • java 中如何获取字节码文件的相关内容

    java 中如何获取字节码文件的相关内容 反射机制是指在运行状态中,对任意一个类(class文件),都能知道这个类的所有属性和方法:对任意一个对象,都能调用这个对象的方法和属性.这种动态的获取信息和动态的调用对象的方法的功能称为--Java语言的反射机制. 简单点说,动态的获取类中的信息,这就是Java的反射机制. 在Java的反射机制中,我们可以通过配置文件信息,然后通过类名来获取类中包含的详细信息,如构造函数.成员变量和成员函数等.在接下来,作者将分别演示如何通过类名来获取类中包含的信息.

  • ASP.NET中实现获取调用方法名

    本文实例讲述了ASP.NET中实现获取调用方法名的技巧.分享给大家供大家参考.具体实现方法如下: 在写记录日志功能时,需要记录日志调用方所在的模块名.命名空间名.类名以及方法名,想到使用的是反射(涉及到反射请注意性能),但具体是哪一块儿还不了解,于是搜索,整理如下: 需要添加相应的命名空间: 复制代码 代码如下: using System; using System.Diagnostics; using System.Reflection; 如果仅是获取当前方法名,可以使用如下代码: 复制代码

  • php中count获取多维数组长度的方法

    本文实例讲述了php中count获取多维数组长度的实现方法.分享给大家供大家参考.具体分析如下: 先来看看下面程序运行结果: 复制代码 代码如下: $numb=array(             array(10,15,30),array(10,15,30),array(10,15,30) );   echo count($numb,1); A.3 B.12 C.6 D.9 答案是B count函数中如果mode被设置为 COUNT_RECURSIVE(或 1),则会递归底计算多维数组中的数组

  • 探讨Smarty中如何获取数组的长度以及smarty调用php函数的详解

    Smarty中如何获取数组的长度 前提假设:分配了一个数组array给Smarty,假设Smarty的分界符为'{' 和'}'.在很多资料上都看到,在Smarty中要求数组的长度时,可以用在数组后便加|count的方法调用.即通过{array|count}获得array的长度.但是今天在写模板时,发现这样得不到数组的长度,而只是得到一个返回的字符串Array.也就是说仅仅是返回了{array}的结果,而没有返回其array的长度. 查看smarty\plugins文件夹,发现并没有count的相

  • PHP实现在数据库百万条数据中随机获取20条记录的方法

    本文实例讲述了PHP实现在数据库百万条数据中随机获取20条记录的方法.分享给大家供大家参考,具体如下: 额,为什么要写这个? 在去某个公司面试时,让写个算法出来,当时就蒙了,我开发过程中用到算法的吗?又不是大数据开发,分析. 今天偶然想起来一个坑爹数据,如:PHP取百万条数据中随机20条记录,当时就用的算法. 1.先统计统计数据库多少条记录(这个做个数据缓存,如1小时重新统计一次), 2.根据总条数,随机1次,1次性取出20条记录(当然这个就相当于分页了,要求不高的话,这个最快,我用的就是这个)

随机推荐