HttpURLConnection 是Java提供的发起HTTP请求的基础类库
三种Http请求的实现
1、Apache --> http client
2、Netty --> http client
3、Spring --> RestTemplate (忽略https安全证书)
一、Apache --》http client
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* http请求实现
*
* @author hooyang
* @date 2019/7/16 10:23
*/
public class HttpClientUtil {
private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);
public HttpClientUtil() {
}
public static String doGet(String url, Map param) {
CloseableHttpClient httpclient = HttpClients.createDefault();
String resultString = "";
CloseableHttpResponse response = null;
try {
URIBuilder builder = new URIBuilder(url);
if (param != null) {
Iterator var6 = param.entrySet().iterator();
while (var6.hasNext()) {
Entry entry = (Entry) var6.next();
builder.addParameter((String) entry.getKey(), (String) entry.getValue());
}
}
URI uri = builder.build();
HttpGet httpGet = new HttpGet(uri);
response = httpclient.execute(httpGet);
if (response.getStatusLine().getStatusCode() == 200) {
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
}
} catch (Exception var16) {
logger.error(var16.getMessage(), var16);
} finally {
try {
if (response != null) {
response.close();
}
httpclient.close();
} catch (IOException var15) {
logger.error(var15.getMessage(), var15);
}
}
return resultString;
}
public static String doGet(String url) {
return doGet(url, (Map) null);
}
public static String doPost(String url, Map param) {
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
HttpPost httpPost = new HttpPost(url);
if (param != null) {
List paramList = new ArrayList();
Iterator var7 = param.entrySet().iterator();
while (var7.hasNext()) {
Entry entry = (Entry) var7.next();
paramList.add(new BasicNameValuePair((String) entry.getKey(), (String) entry.getValue()));
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList, "utf-8");
httpPost.setEntity(entity);
}
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception var17) {
logger.error(var17.getMessage(), var17);
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException var16) {
logger.error(var16.getMessage(), var16);
}
}
return resultString;
}
public static String doPost(String url) {
return doPost(url, (Map) null);
}
public static String doPostJson(String url, String json) {
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
HttpPost httpPost = new HttpPost(url);
StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
httpPost.setEntity(entity);
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception var15) {
logger.error(var15.getMessage(), var15);
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException var14) {
logger.error(var14.getMessage(), var14);
}
}
return resultString;
}
}
二、Netty --》http client
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;
import java.net.URI;
public class HttpClient {
private String host;
private int port;
private String requri;
private String reqmsg;
final HttpClientHandler clientHandler;
public HttpClient() {
clientHandler = new HttpClientHandler();
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getRequri() {
return requri;
}
public void setRequri(String requri) {
this.requri = requri;
}
public String getReqmsg() {
return reqmsg;
}
public void setReqmsg(String reqmsg) {
this.reqmsg = reqmsg;
}
@SuppressWarnings("finally")
public String connect() throws Exception {
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.SO_KEEPALIVE, true);
b.handler(new ChannelInitializer() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
// 客户端接收到的是httpResponse响应,所以要使用HttpResponseDecoder进行解码
ch.pipeline().addLast(new HttpResponseDecoder());
// 客户端发送的是httprequest,所以要使用HttpRequestEncoder进行编码
ch.pipeline().addLast(new HttpRequestEncoder());
ch.pipeline().addLast(new NioEventLoopGroup());
ch.pipeline().addLast(clientHandler);
}
});
ChannelFuture f = b.connect(host, port).sync();
URI uri = new URI(requri);
DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST,
uri.toASCIIString(), Unpooled.wrappedBuffer(reqmsg.getBytes()));
// 构建http请求
request.headers().set(HttpHeaderNames.HOST, host);
request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderNames.CONNECTION);
request.headers().set(HttpHeaderNames.CONTENT_LENGTH, request.content().readableBytes());
// 发送http请求
f.channel().write(request);
f.channel().flush();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
return clientHandler.getResStr();
}
}
}
三、Spring --》RestTemplate
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* http请求实现
*
* @author hooyang
* @date 2019/7/16 10:23
*/
public class RestTemplateUtil {
private static Logger logger = LoggerFactory.getLogger(RestTemplateUtil.class);
public RestTemplateUtil() {
}
/**
*
*
* @param url
* @param securityValue
* @return
*/
public static String postForEntity(String url, String securityValue) {
String reData = "";
try {
// RestTemplate template = new RestTemplate();
RestTemplate template = new RestTemplate(generateHttpRequestFactory());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType(MediaType.APPLICATION_FORM_URLENCODED + "; charset=UTF-8"));
//参数放入一个map中,restTemplate不能用hashMap
MultiValueMap param = new LinkedMultiValueMap();
param.add("securityMsg", securityValue);
//将参数和header组成一个请求
HttpEntity> request = new HttpEntity>(param, headers);
ResponseEntity response = template.postForEntity(url, request, String.class);
logger.debug("postForEntity reStatusCode:=" + response.getStatusCode());
logger.debug("postForEntity reHeaders:=" + response.getHeaders());
logger.debug("postForEntity reBody:=" + response.getBody());
reData = response.getBody();
} catch (Exception e) {
e.printStackTrace();
}
return reData;
}
/**
* RestTemplete 忽略安全证书
*
* @return
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
* @throws KeyStoreException
*/
private static HttpComponentsClientHttpRequestFactory generateHttpRequestFactory()
throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
// TrustStrategy acceptingTrustStrategy = (x509Certificates, authType) -> true;
TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
return true;
}
};
SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
SSLConnectionSocketFactory connectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
HttpClientBuilder httpClientBuilder = HttpClients.custom();
httpClientBuilder.setSSLSocketFactory(connectionSocketFactory);
CloseableHttpClient httpClient = httpClientBuilder.build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setHttpClient(httpClient);
return factory;
}
}
1、Apache --》http client 是阻塞式的读取 Http request(异步读写网络数据性能更好些)。当 client 到 server 的连接中断时,http client 无法感知到这件事的发生,需要开发者主动的轮训校验
2、Netty --》http client 是事件驱动的,逻辑主要基于回调函数。数据包到来了也好,网络连接中断也好,都要通过写回调函数确定这些事件来临后的后续操作
3、Spring --》RestTemplate 简化了发起HTTP请求以及处理响应的过程,并且支持REST
RestTemplate能大幅简化了提交表单数据的难度,并且附带了自动转换JSON数据的功能,但只有理解了HttpEntity的组成结构(header与body),且理解了与uriVariables之间的差异,才能真正掌握其用法
REST(RepresentationalState Transfer)是Roy Fielding 提出的一个描述互联系统架构风格的名词。REST定义了一组体系架构原则,您可以根据这些原则设计以系统资源为中心的Web 服务
1、REST成熟度的四个层次
第一个层次(Level0)的Web 服务,只是使用 HTTP 作为传输方式,实际上只是远程方法调用(RPC)的一种具体形 式。SOAP和 XML-RPC都属于此类。
第二个层次(Level1)的Web 服务,引入了资源的概念。每个资源有对应的标识符和表达。
第三个层次(Level2)的Web 服务,使用不同的 HTTP 方法来进行不同的操作,并且使用HTTP 状态码来表示不同的结果。如 HTTPGET 方法来获取资源,HTTPDELETE 方法来删除资源。
第四个层次(Level3)的Web 服务,使用 HATEOAS。在资源的表达中包含了链接信息。客户端可以根据链接来发现可以执行的动作。
其中第三个层次建立了创建、读取、更新和删除(create,read, update, and delete,CRUD)操作与 HTTP方法之间的一对一映射。根据此映射:
(1)若要在服务器上创建资源,应该使用POST 方法。
(2)若要检索某个资源,应该使用GET 方法。
(3)若要更改资源状态或对其进行更新,应该使用PUT 方法。
(4)若要删除某个资源,应该使用DELETE 方法。
2、HTTP请求的状态码
(1)成功Successful 2xx:此类状态码标识客户端的请求被成功接收、理解并接受。常见如200(OK)、204(NoContent)。
(2)重定向Redirection 3xx:这个类别的状态码标识用户代理要做出进一步的动作来完成请求。常见如301(MovedPermanently)、302(MovedTemprarily)。
(3)客户端错误Client Error 4xx:4xx类别的状态码是当客户端象是出错的时使用的。常见如400(BadRequest)、401(Unauthorized)、403(Forbidden)、404(NotFound)。
(4)服务器错误Server Error 5xx:响应状态码以5开头表示服务器知道自己出错或者没有能力执行请求。常见如500(InternalServer Error)、502(BadGateway)、504(GatewayTimeout)。