Spring Boot教程(24) – 用RestTemplate访问外部服务
标签: Spring Boot教程(24) – 用RestTemplate访问外部服务 spring boot博客 51CTO博客
2023-07-19 18:24:32 177浏览
日常开发中难免会向应用外部发起HTTP请求,比如访问云存储平台的API、调用微信或支付宝的API、抓取网页等等。Spring框架提供了RestTemplate
来完成这一需求。RestTemplate
提供了很多方法,方便你发起GET和POST等请求。下图是个简单的调用,去获取网页的HTML代码:
getForEntity方法会发起GET请求,然后返回一个ResponseEntity
对象,它把HTTP请求的响应抽象成一个对象。通过ResponseEntity
,你可以获取到此次响应的状态码、首部(Header)和主体(Body)。有的时候你仅仅需要Body部分,那就可以使用getForObject方法。
Spring Boot对RestTemplate
也做了自动配置,但是他并没有提供给一个全局的RestTemplate
对象,而是给了个全局的RestTemplateBuilder
对象,你可以在需要的时候,build一个RestTemplate
出来,像下面一样:
Spring Boot在创建了RestTemplateBuilder
之后,还给他配置了很多HttpMessageConverter
,它的作用是把HTTP请求中的Body转化为Java中的对象,或者把对象转化为Body。我们看看上面的getForObject方法,第二个参数是个Class对象,告诉RestTemplate
你想把Body转化成什么类型的对象,如果你传递了String.class,那么StringHttpMessageConverter
就会将Body转换成String对象。如果你传递了byte[].class,那么ByteArrayHttpMessageConverter
会把Body转化成byte[]对象,如果你传递了某个JSON映射类,MappingJackson2HttpMessageConverter
会把Body转化成这个映射类的对象。更多相关信息,你可以查看HttpMessageConvertersAutoConfiguration
和RestTemplateAutoConfiguration
的源码。
我们再来看看RestTemplate所提供的一些方法:
GET请求
POST请求
DELETE请求
除了上面三张图中的GET、POST和DELETE方法,RestTemplate
还有一些类似的方法来发起HEAD、OPTIONS、PUT、PATCH等请求。从这些方法的命名和参数可以看出,RestTemplate
的风格很RESTful,如果你访问的网络服务的API是这种风格的话,那么使用起来会非常顺手。
底层HTTP库
RestTemplate
是比较高阶的接口,它利用了底层的HTTP库,底层的HTTP库有多种选择:
- Apache HttpComponents
- java.net.HttpURLConnection
- OkHttp
Spring为了方便你在这些这些库之间进行切换,实现了不同的ClientHttpRequestFactory
,你选择了不同的库,就需要给RestTemplate
设置不同的ClientHttpRequestFactory
,上面三种库分别对应下面三个类:
- HttpComponentsClientHttpRequestFactory
- SimpleClientHttpRequestFactory
- OkHttp3ClientHttpRequestFactory
当你需要的时候,可以创建一个ClientHttpRequestFactory
对象,传给RestTemplate
。当然,一般情况下,你不必像上图这么做。Spring Boot会看看你的类路径下有没有HttpComponents,有的话就用,没有的话看看有没有OkHttp,最后才是保底的HttpUrlConnection。如果你想使用OkHttp,可以直接在build.gradle里加上依赖,其他啥都不用做。
值得一提的是,OkHttp对应的是OkHttp3ClientHttpRequestFactory
,但是目前OkHttp的版本已经到4.x了,是不是应该再找一个OkHttp4ClientHttpRequestFactory
呢?其实4.x版本只是用Kotlin把OkHttp重新写了一遍,接口并没有改变,还是兼容3.x的。另外你可能要问,我项目用的是Java,OkHttp用的是Kotlin,是不是我就不能在项目里用了呀?其实不是,虽然你在Intellij IDEA里跳入OkHttp源码时看到的是Kotlin代码,但是实际项目编译的时候,你引入的是Kotlin编译过之后的class文件,所以说加入4.x版本的OkHttp照样能用。
URI模板
在给RestTemplate
传递链接的时候,可以给链接里设置占位符,方便之后通过它来动态生成链接。下图中,链接中的”userId”占位符的位置之后会被替换成10。
我刚开始没有研究API的时候,发现getForEntity方法的第三个参数是Map类型,自然而然地以为它是用来传递请求参数的(request parameter或者说query parameter),后来运行的时候才发现不对。如果你想传递请求参数,那么你可能需要使用UriComponentsBuilder
来修改链接。
自定义Header
如果你想给请求自定义Header,直接用getForObject或者postForObject这种方法可能做不到。这个时候,就需要使用更加通用的exchange方法:
一个HTTP请求,说白了也就这4个东西需要设定:HTTP方法、URL、Header和Body。exchange的这么多种重载方法就是变着花样方便你去传递这四个东西。你在上面这些方法中可能没直接看到设置Header的地方,因为Header被包含在HttpEntity
类中,HttpEntity
= HttpHeaders
+ Body。另外,你还可以使用RequestEntity
去构造一个请求。RequestEntity
继承于HttpEntity
,相当于RequestEntity
= HttpEntity
+ url + HTTP方法。
如果你想给每个请求都加上特定的Header,可以通过拦截器实现:
我在写上面的代码的时候发现了一个巨坑。RestTemplateBuilder
每次设定过之后,会返回一个新的RestTemplateBuilder
,也就是说,在上图中,builder和newBuilder不是同一个对象,这好像跟我们以前所接触过的各种Builder不太一样,以前的Builder每次设置了之后都会返回this,而RestTemplateBuilder
会去new一个新的对象,刚开始我感觉不太合理,没必要这么做。后来想想,因为Spring Boot会默认提供一个全局的RestTemplateBuilder
,如果一个类对它进行了修改,其他类获取RestTemplateBuilder
的时候就是修改过的了,可能会产生副作用。
上面我们说了给单个RestTemplate
的所有请求都添加Header的方法,下面说说给所有RestTemplate
添加Header的方法。RestTemplateCustomizer
是用来对RestTemplate
进行修改的类,我们在容器中扔这样一个RestTemplateCustomizer
对象,那么Spring Boot在创建RestTemplateBuilder
的时候,会自动把它提供给RestTemplateBuilder
,这样每个RestTemplate
都可以自定义了:
虽然上面我们的例子写的是给请求添加Header,但是你可以做的更多,总的来说,就是框架给了你一种能力:可以对单个请求、单个RestTemplate
、以及所有RestTemplate
进行自定义。我们可以看出,RestTemplate
的设计还是非常灵活方便的。
异常处理
默认情况下,遇到4xx错误,或者5xx错误的时候,会抛出异常,不同的状态码有不同的异常,可能的异常如下图:
捕获异常之后,你还可以从异常对象中获取状态码、Header和Body,以便根据不同的错误信息做不同的处理。如果你对默认的异常处理机制不满意,可以自定义一个ResponseErrorHandler
传递给RestTemplate
,不过我觉得默认的就挺好,没必要再搞一套。
最后
本文介绍了日常开发可能用到的接口和场景,还有一些比较细节的东西还可以挖掘,比如通过Multipart请求上传文件等等。除了RestTemplate
,你还可以选择WebClient
这种非阻塞、响应式的请求工具,它通常和WebFlux一起使用。另外你还可以用Retrofit和Feign来通过编写接口方法+注解来定义HTTP请求,使用起来非常简单和容易,我个人很喜欢这种工具,接下来肯定会写一篇文章来总结他们的用法的。
好博客就要一起分享哦!分享海报
此处可发布评论
评论(0)展开评论
展开评论