HttpClient-RestTemplate-Feign
如何通过Java发送HTTP请求,通俗点讲,如何通过Java(模拟浏览器)发送HTTP请求。
Java有原生的API可用于发送HTTP请求,即java.net.URL、java.net.URLConnection,这些API很好用、很常用,但不够简便;
所以,也流行有许多Java HTTP请求的framework,如,Apache的HttpClient。
httpclient之外RPC 以及队列的使用看可以说也是越来越广泛了。
在netty等NIO框架因为需要高效的传输所以往往选择RPC,队列则用于回调以及设备消息之间的传递。
Http这个经久不衰的大佬自然不用多说,简单,支持广泛,高度兼容性。
HttpClient
HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性,使得客户端发送Http请求变得容易。
HttpClient使用:
使用HttpClient发送请求、接收响应很简单,一般需要如下几步即可。
1. 创建HttpClient对象。
2. 创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。
3. 如果需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HetpParams params)方法来添加请求参数;对于HttpPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数。
4. 调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse。
5. 调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。
6. 释放连接。无论执行方法是否成功,都必须释放连接
RestTemplate
RestTemplate本是spring-web项目中的一个REST客户端,它遵循REST的设计原则,提供简单的API让我们可以调用HTTP服务。底层是对httpclient进行了封装。

ps:建议使用exchange ,其他方法都是对execute进行了封装,都拥有各自的局限性。
RestTemplate可以用来做负载均衡,RestTemplate本身不具有负载均衡的功能,该类也与Spring Cloud没有关系,但为何加入@LoadBalanced注解后,一个RestTemplate实例就具有负载均衡的功能呢?
实际上这要得益于RestTemplate的拦截器功能。
下面举例:基于自己配置的HttpClient,创建一个可负载均衡的RestTemplate
HttpClientProperties
HttpClient的配置信息
@ConfigurationProperties(prefix="spring.httpclient")
public class HttpClientProperties { private Integer connectTimeOut = ; private Integer socketTimeOut = ; private String agent = "agent";
private Integer maxConnPerRoute = ;
private Integer maxConnTotaol = ;
public Integer getConnectTimeOut() {
return connectTimeOut;
}
public void setConnectTimeOut(Integer connectTimeOut) {
this.connectTimeOut = connectTimeOut;
}
public Integer getSocketTimeOut() {
return socketTimeOut;
}
public void setSocketTimeOut(Integer socketTimeOut) {
this.socketTimeOut = socketTimeOut;
}
public String getAgent() {
return agent;
}
public void setAgent(String agent) {
this.agent = agent;
}
public Integer getMaxConnPerRoute() {
return maxConnPerRoute;
}
public void setMaxConnPerRoute(Integer maxConnPerRoute) {
this.maxConnPerRoute = maxConnPerRoute;
}
public Integer getMaxConnTotaol() {
return maxConnTotaol;
}
public void setMaxConnTotaol(Integer maxConnTotaol) {
this.maxConnTotaol = maxConnTotaol;
} }
HttpClientAutoConfiguration
根据HttpClient.class是否存在,bean是否存在,自动进行配置
@Configuration
@ConditionalOnClass({HttpClient.class})
@EnableConfigurationProperties(HttpClientProperties.class)
public class HttpClientAutoConfiguration { private final HttpClientProperties properties; public HttpClientAutoConfiguration(HttpClientProperties properties){
this.properties = properties;
} /**
* httpclient bean 的定义
* @return
*/
@Bean
@ConditionalOnMissingBean(HttpClient.class)
public HttpClient httpClient() {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(properties.getConnectTimeOut())
.setSocketTimeout(properties.getSocketTimeOut()).build();// 构建requestConfig
HttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig)
.setUserAgent(properties.getAgent())
.setMaxConnPerRoute(properties.getMaxConnPerRoute())
.setMaxConnTotal(properties.getMaxConnTotaol())
.build();
return client;
}
}
@ConditionalOnClass:该注解的参数对应的类必须存在,否则不解析该注解修饰的配置类;
@ConditionalOnMissingBean:该注解表示,如果存在它修饰的类的bean,则不需要再创建这个bean;可以给该注解传入参数例如@ConditionOnMissingBean(name = "example"),这个表示如果name为“example”的bean存在,这该注解修饰的代码块不执行。
RestAutoConfig
创建负载均衡和直连的RestTemplate
@Configuration
public class RestAutoConfig { public static class RestTemplateConfig { @Bean//负载均衡的restTemplate
@LoadBalanced //spring 对restTemplate bean进行定制,加入loadbalance拦截器进行ip:port的替换
//"http://user/getusername,就能解析成http://127.0.0.1:8083//getusername
RestTemplate lbRestTemplate(HttpClient httpclient) {
RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpclient));
template.getMessageConverters().add(,new StringHttpMessageConverter(Charset.forName("utf-8")));
template.getMessageConverters().add(,new FastJsonHttpMessageConvert5());
return template;
} @Bean //直连的restTemplat,这时只能使用http://127.0.0.1:8083//getusername地址,不能解析http://user/getusername
RestTemplate directRestTemplate(HttpClient httpclient) {
RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpclient));
template.getMessageConverters().add(,new StringHttpMessageConverter(Charset.forName("utf-8")));
template.getMessageConverters().add(,new FastJsonHttpMessageConvert5());
return template;
} // FastJsonHttpMessageConvert4有一个bug,它是默认支持MediaType.ALL,spring在处理MediaType.ALL的时候会识别成字节流,而不是json,这里就对他进行改造和处理
public static class FastJsonHttpMessageConvert5 extends FastJsonHttpMessageConverter4{ static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); public FastJsonHttpMessageConvert5(){
setDefaultCharset(DEFAULT_CHARSET);
setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON,new MediaType("application","*+json")));
} }
} }
调用RestTemplate的默认构造函数,RestTemplate对象在底层通过使用java.net包下的实现创建HTTP 请求,可以通过使用ClientHttpRequestFactory指定不同的HTTP请求方式。
ClientHttpRequestFactory接口主要提供了两种实现方式
- 一种是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)创建底层的Http请求连接。
- 一种方式是使用HttpComponentsClientHttpRequestFactory方式,底层使用HttpClient访问远程的Http服务,使用HttpClient可以配置连接池和证书等信息。
GenericRest
既支持直连又支持服务发现的调用
/**
* 既支持直连又支持服务发现的调用
*
*/
@Service
public class GenericRest { @Autowired
@Qualifier("lbRestTemplate")
private RestTemplate lbRestTemplate; @Autowired
@Qualifier("directRestTemplate")
private RestTemplate directRestTemplate; private static final String directFlag = "direct://"; //返回的泛型用ParameterizedTypeReference<T>来指定
public <T> ResponseEntity<T> post(String url,Object reqBody,ParameterizedTypeReference<T> responseType){
RestTemplate template = getRestTemplate(url);
url = url.replace(directFlag, "");
return template.exchange(url, HttpMethod.POST,new HttpEntity(reqBody),responseType);
} public <T> ResponseEntity<T> get(String url,ParameterizedTypeReference<T> responseType){
RestTemplate template = getRestTemplate(url);
url = url.replace(directFlag, "");
return template.exchange(url, HttpMethod.GET,HttpEntity.EMPTY,responseType);
} private RestTemplate getRestTemplate(String url) {
if (url.contains(directFlag)) {
return directRestTemplate;
}else {
return lbRestTemplate;
}
} }
exchange支持‘含参数的类型’(即泛型类)作为返回类型,该特性通过‘ParameterizedTypeReference<T>responseType’描述。
进行服务调用:
public List<User> getUserList(User query) {
ResponseEntity<RestResponse<List<User>>> resultEntity = rest.post("http://"+ userServiceName + "/user/getList",query, new ParameterizedTypeReference<RestResponse<List<User>>>() {});
RestResponse<List<User>> restResponse = resultEntity.getBody();
if (restResponse.getCode() == ) {
return restResponse.getResult();
}else {
return null;
}
}
SpringCloud Feign—申明式服务调用
虽然RestTemplate已经可以将请求拦截来实现对依赖服务的接口调用,并对Http请求进行封装处理,形成一套模板化的调用方法,但是对服务依赖的调用可能不只一处,一个接口都会被多次调用,所以我们会像前面那样针对各个微服务字形封装一些客户端接口调用类来包装这些依赖服务的调用。
由于RestTemplate的封装,几乎每一个调用都是简单的模板化内容,Feign在此基础上做了进一步的封装,由它来帮助我们定义和实现依赖服务接口的定义。
在服务消费者创建服务调用接口,通过@FeignClient注解指定服务名来绑定服务,然后再使用SpringMVC的注解来绑定具体该服务提供的REST接口。
@FeignClient("biz-service-0")
public interface UserClient {
@RequestMapping(method = RequestMethod.GET, value = "/getuser")
public User getuserinfo();
@RequestMapping(method = RequestMethod.GET, value = "/getuser")
public String getuserinfostr();
}
在服务消费者的web层进行调用:
@RestController
public class UserController { @Autowired
UserClient userClient; @RequestMapping(value = "/getuserinfo", method = RequestMethod.GET)
public User getuserinfo() {
return userClient.getuserinfo();
}
@RequestMapping(value = "/getuserinfostr", method = RequestMethod.GET)
public String getuserinfostr() {
return userClient.getuserinfostr(); }
通过Feign我们只需要定义服务绑定接口,以申明式的方法,优雅而简单的实现了服务调用。
HttpClient-RestTemplate-Feign的更多相关文章
- [Spring-Cloud-Alibaba] Sentinel 整合RestTemplate & Feign
Sentinel API Github : WIKI Sphu (指明要保护的资源名称) Tracer (指明调用来源,异常统计接口) ContextUtil(标示进入调用链入口) 流控规则(针对来源 ...
- Java实现远程服务生产与消费(RPC)的4种方法-RMI,WebService,HttpClient,RestTemplate
目录 一. 通过rmi实现远程服务的生产与消费 远程服务提供者实现. 创建rmi-provider项目(Maven) 远程服务消费者实现 创建rmi-consumer项目 二. 通过WebServic ...
- HttpClient&&RestTemplate学习
1. 什么是HttpClient HttpClient是Apache下面的子项目,可以提供高效的,最新的,功能丰富的支持HTTP协议的客户端编程工具包. 2. 为什么要学习HttpClient Htt ...
- Httpclient与RestTemplate的比较(比httpClient更优雅的Restful URL访问)
一.HttpClient (一)HttpClient 客户端 1.HttpClient 是 apache 的开源,需要引入两个包:httpclient-4.2.4.jar 和 httpcore-4.2 ...
- SpringBoot系列: RestTemplate 快速入门
====================================相关的文章====================================SpringBoot系列: 与Spring R ...
- spring cloud 声明式rest客户端feign调用远程http服务
在Spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端.Feign就是Spring Cloud提供的一种声明式R ...
- 使用Spring Cloud Feign作为HTTP客户端调用远程HTTP服务
在Spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端.我们可以使用JDK原生的URLConnection.Ap ...
- RestTemplate发送HTTP、HTTPS请求
RestTemplate 使用总结 场景: 认证服务器需要有个 http client 把前端发来的请求转发到 backend service, 然后把 backend service 的结果再返 ...
- 使用Spring Cloud Feign
使用Spring Cloud Feign作为HTTP客户端调用远程HTTP服务 在spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就 ...
- 客户端远程调用Feign
客户端远程调用 Feign 什么是Feign? Feign是 Netflix 公司开源的声明式HTTP客户端 Github : Feign 源码 为什么需要Feign? 原代码可读性不高 复杂的URL ...
随机推荐
- MinGW和MSYS的自动安装 【转】
好吧,这是今天写的第二篇文章.我表示这篇才是今天的重头.(伪 半年之前曾经写过一篇关于MinGW和MSYS的手动安装的文章[1],到现在还是全站点击率最高的.(目前这篇文章是最高的.)好吧,侧面反映了 ...
- C语言之顺序结构
该章内容:这章我们学习三大结构之一:顺序结构,它是程序从上往下顺序执行,是程序运行最简单的方式.printf和scanf函数使用和特例是必考知识.本章是考试的重点章节. 学习方法:从简单的顺序结构题目 ...
- 【mysql】查看版本的四种方法
1:在终端下:mysql -V. 以下是代码片段: [test@login ~]$ mysql -V mysql Ver 14.7 Distrib 4.1.10a, for redhat-linux- ...
- LeetCode——Single Number III
Description: Given an array of numbers nums, in which exactly two elements appear only once and all ...
- Docker 使用指南 (三)—— 网络配置
版权声明:本文由田飞雨原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/95 来源:腾云阁 https://www.qclou ...
- Ubuntu 如何更改用户密码
你需要为第一个帐户创建一个密码.这可以用 passwd 命令来完成. 系统会提示输入你的旧密码一次,输入你的新密码两次.用 root 用户更改用户 paul 的密码[root@bigboy root] ...
- Android内存优化总结【整理】
http://blog.csdn.net/tiantangrenjian/article/details/39182293 [前段时间接到任务着手进行app的内存优化,从各种各样的渠道搜索相关资料,最 ...
- centos7上安装iptables
centos7上安装iptables的步骤 注意:CentOS7默认的防火墙不是iptables,而是firewalle. 安装iptable iptable-service #安装iptables ...
- 【BZOJ4418】[Shoi2013]扇形面积并 扫描线+线段树
[BZOJ4418][Shoi2013]扇形面积并 Description 给定N个同心的扇形,求有多少面积,被至少K个扇形所覆盖. Input 第一行是三个整数n,m,k.n代表同心扇形的个数,m用 ...
- Unity3D 笔记二 3D模型基础
一.3D模型基础 1.Hierarchy 显示的是界面上的游戏对象(GameObject),每个游戏对象都有.至少要有一个Camera,点击Camera就可以在Preview中看到摄像机的视角画面.每 ...