如何通过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的更多相关文章

  1. [Spring-Cloud-Alibaba] Sentinel 整合RestTemplate & Feign

    Sentinel API Github : WIKI Sphu (指明要保护的资源名称) Tracer (指明调用来源,异常统计接口) ContextUtil(标示进入调用链入口) 流控规则(针对来源 ...

  2. Java实现远程服务生产与消费(RPC)的4种方法-RMI,WebService,HttpClient,RestTemplate

    目录 一. 通过rmi实现远程服务的生产与消费 远程服务提供者实现. 创建rmi-provider项目(Maven) 远程服务消费者实现 创建rmi-consumer项目 二. 通过WebServic ...

  3. HttpClient&&RestTemplate学习

    1. 什么是HttpClient HttpClient是Apache下面的子项目,可以提供高效的,最新的,功能丰富的支持HTTP协议的客户端编程工具包. 2. 为什么要学习HttpClient Htt ...

  4. Httpclient与RestTemplate的比较(比httpClient更优雅的Restful URL访问)

    一.HttpClient (一)HttpClient 客户端 1.HttpClient 是 apache 的开源,需要引入两个包:httpclient-4.2.4.jar 和 httpcore-4.2 ...

  5. SpringBoot系列: RestTemplate 快速入门

    ====================================相关的文章====================================SpringBoot系列: 与Spring R ...

  6. spring cloud 声明式rest客户端feign调用远程http服务

    在Spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端.Feign就是Spring Cloud提供的一种声明式R ...

  7. 使用Spring Cloud Feign作为HTTP客户端调用远程HTTP服务

    在Spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端.我们可以使用JDK原生的URLConnection.Ap ...

  8. RestTemplate发送HTTP、HTTPS请求

    RestTemplate 使用总结   场景: 认证服务器需要有个 http client 把前端发来的请求转发到 backend service, 然后把 backend service 的结果再返 ...

  9. 使用Spring Cloud Feign

    使用Spring Cloud Feign作为HTTP客户端调用远程HTTP服务 在spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就 ...

  10. 客户端远程调用Feign

    客户端远程调用 Feign 什么是Feign? Feign是 Netflix 公司开源的声明式HTTP客户端 Github : Feign 源码 为什么需要Feign? 原代码可读性不高 复杂的URL ...

随机推荐

  1. N76E003学习之路(二)

    最近一直在想N76E003和STM8M003的对比情况,在网上找了不少资料,看了不少文档,具体总结如下: STM8S003F3P6:一共20个脚,最多支持16个GPIO,支持16个外部中断:2个16位 ...

  2. qq邮箱发送,mail from address must be same as authorization user

    由于邮箱发送的邮箱账号更换,所以重新测试.结果一直出错,要不就是请求超时,要不就是未授权. 用smtp 开始的时候,端口使用495,结果是请求超时. 后来改成25,结果是未授权. 再后来听人说,有一个 ...

  3. java基础---->多线程之yield(三)

    yield方法的作用是放弃当前的CPU资源,将它让给其它的任务去占用CPU执行时间.但放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片.今天我们通过实例来学习一下yield()方法的使用.最是 ...

  4. Ubuntu adb devices :???????????? no permissions (verify udev rules) 解决方法

    Ubuntu adb devices :???????????? no permissions (verify udev rules) 解决方法http://www.cnblogs.com/cat-l ...

  5. C#8.0中的 await foreach

    AsyncStreamsInCShaper 8.0 C# 8.0中支持异步返回枚举类型async Task<IEnumerable<T>> sync Streams这个功能已经 ...

  6. Lucene构建索引时的一些概念和索引构建的过程

    在搜索文档内容之前要做的事情就是对从各种不同来源(网页,数据库,电子邮件等)的文档进行索引,索引的过程就是对内容进行提取,规范化(通过对内容进行建模来实现),然后存储. 在索引的过程中有几个基本的概念 ...

  7. Windows Phone 独立存储查看器

    1.为了查看我们存放在独立存储的数据,我们需要借助独立存储查看器. 2.简单介绍下,IsoStoreSpy 下载地址:http://download.csdn.net/download/lhb1097 ...

  8. mysql 内连接原理

  9. postgresql----字符串函数与操作符

    函数 返回值类型 描述 示例 结果 string||string text 字符串连接 select 'Post'||'gresql'||' good!'; Postgresql good! stri ...

  10. Shell--基础知识

    变量的定义: a=1 b=hello c="hello world !" d='hello "反启" !' e=`ls`  (注意:这是反引号) 备注:=号左右 ...