如何通过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. 如何设置SOLR的高亮 (highlight)?

    打开SOLR的核心配置文件: solrconfig.xml 找到 standard request handler 写入以下XML配置代码: <requestHandler name=" ...

  2. C++新式转型

    本文对四种标准C++的类型转换符:static_cast.dynamic_cast.reinterpret_cast.和const_cast进行了介绍,通过本文应当能够理解这四个类型转换操作符的含义. ...

  3. iOS 自动布局 Autolayout 优先级的使用

    一.约束的优先级 0.屏幕适配 发展历程 代码计算frame -> autoreszing(父控件和子控件的关系) -> autolayout(任何控件都可以产生关系) -> siz ...

  4. CSS-布局样式之筛选条件右边线的处理方法(no CSS3)

    先上图:

  5. 【文智背后的奥秘】系列篇——基于CRF的人名识别

    版权声明:本文由文智原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/133 来源:腾云阁 https://www.qclou ...

  6. hihocoder [Offer收割]编程练习赛14 投掷硬币

    题目2 : 投掷硬币 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi有一枚神奇的硬币.已知第i次投掷这枚硬币时,正面向上的概率是Pi. 现在小Hi想知道如果总共投 ...

  7. POJ2286 The Rotation Game[IDA*迭代加深搜索]

    The Rotation Game Time Limit: 15000MS   Memory Limit: 150000K Total Submissions: 6325   Accepted: 21 ...

  8. [C/C++] String Reverse 字符串 反转

    #include <iostream> #include <string> #include <algorithm> #include <cstring> ...

  9. jfinal的controller默认访问的方法是什么

    index()方法: 如: @Controller("/test/exam")public class TestController 如下请求请求:http://localhost ...

  10. 设备信息的管理(Device) ---- HTML5+

    模块:Device Device模块管理设备信息,用于获取手机设备的相关信息,如IMEI.IMSI.型号.厂商等.通过plus.device获取设备信息管理对象. 应用场景:打电话,铃声提醒,震动提醒 ...