客戶端http協(xié)議傳輸類庫(kù)。HttpClient被用來(lái)發(fā)送和接受Http消息。HttpClient不會(huì)處理Http消息的內(nèi)容,不會(huì)進(jìn)行Javascript解析,不會(huì)關(guān)心ContentType,如果沒(méi)有明確設(shè)置,HttpClient也不會(huì)對(duì)請(qǐng)求進(jìn)行格式化、重定向url,或者其他任何和http消息傳輸相關(guān)的功能。
HttpClient核心接口
org.apache.http.HttpMessage:HTTP 消息由客戶端到服務(wù)器的請(qǐng)求和服務(wù)器到客戶端的響應(yīng)組成。
org.apache.http.HttpRequest:從客戶端到服務(wù)器的請(qǐng)求消息在該消息的第一行中包括要應(yīng)用于資源的方法、資源的標(biāo)識(shí)符和正在使用的協(xié)議版本。
org.apache.http.client.HttpClient:這個(gè)接口只代表了 HTTP 請(qǐng)求執(zhí)行的最基本的合約。它對(duì)請(qǐng)求執(zhí)行過(guò)程沒(méi)有施加任何限制或特定細(xì)節(jié),并將狀態(tài)管理、身份驗(yàn)證和重定向處理的細(xì)節(jié)留給單獨(dú)的實(shí)現(xiàn)。
org.apache.http.HttpResponse:在接收并解釋請(qǐng)求消息后,服務(wù)器以 HTTP 響應(yīng)消息進(jìn)行響應(yīng)。
核心依賴
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
HttpClient入?yún)?/h3>
實(shí)體入?yún)⒌恼?qǐng)求需要繼承HttpEntityEnclosingRequestBase,官方HttpDelete/HttpPatch/HttpPost/HttpPut均支持實(shí)體入?yún)?/strong>
public abstract class HttpEntityEnclosingRequestBase
extends HttpRequestBase implements HttpEntityEnclosingRequest {
private HttpEntity entity;
public HttpEntityEnclosingRequestBase() {
super();
}
@Override
public HttpEntity getEntity() {
return this.entity;
}
@Override
public void setEntity(final HttpEntity entity) {
this.entity = entity;
}
@Override
public boolean expectContinue() {
final Header expect = getFirstHeader(HTTP.EXPECT_DIRECTIVE);
return expect != null && HTTP.EXPECT_CONTINUE.equalsIgnoreCase(expect.getValue());
}
@Override
public Object clone() throws CloneNotSupportedException {
final HttpEntityEnclosingRequestBase clone =
(HttpEntityEnclosingRequestBase) super.clone();
if (this.entity != null) {
clone.entity = CloneUtils.cloneObject(this.entity);
}
return clone;
}
}
無(wú)需實(shí)體入?yún)⒌恼?qǐng)求可以直接繼承HttpRequestBase,官方HttpGet/HttpHead/HttpOptions/HttpTrace均不支持實(shí)體入?yún)ⅲ瑢?shí)在有需要可以自行重寫(xiě),直接繼承HttpEntityEnclosingRequestBase即可
public abstract class HttpRequestBase extends AbstractExecutionAwareRequest
implements HttpUriRequest, Configurable {
private ProtocolVersion version;
private URI uri;
private RequestConfig config;
@Override
public abstract String getMethod();
/**
* @since 4.3
*/
public void setProtocolVersion(final ProtocolVersion version) {
this.version = version;
}
@Override
public ProtocolVersion getProtocolVersion() {
return version != null ? version : HttpProtocolParams.getVersion(getParams());
}
@Override
public URI getURI() {
return this.uri;
}
@Override
public RequestLine getRequestLine() {
final String method = getMethod();
final ProtocolVersion ver = getProtocolVersion();
final URI uriCopy = getURI(); // avoids possible window where URI could be changed
String uritext = null;
if (uriCopy != null) {
uritext = uriCopy.toASCIIString();
}
if (uritext == null || uritext.isEmpty()) {
uritext = "/";
}
return new BasicRequestLine(method, uritext, ver);
}
@Override
public RequestConfig getConfig() {
return config;
}
public void setConfig(final RequestConfig config) {
this.config = config;
}
public void setURI(final URI uri) {
this.uri = uri;
}
public void started() {
}
public void releaseConnection() {
reset();
}
@Override
public String toString() {
return getMethod() + " " + getURI() + " " + getProtocolVersion();
}
}

HttpEntity:HTTP 消息發(fā)送或接收的實(shí)體,HttpEntityEnclosingRequestBase中的屬性
public interface HttpEntity {
//實(shí)體是否能夠多次生成其數(shù)據(jù)。可重復(fù)實(shí)體的 getContent() 和 writeTo(OutputStream) 方法可以多次調(diào)用,而不可重復(fù)實(shí)體則不能。
boolean isRepeatable();
//實(shí)體的分塊編碼。HTTP1.0不支持分塊。此方法的主要目的是指示在發(fā)送實(shí)體時(shí)是否應(yīng)使用分塊編碼。對(duì)于接收到的實(shí)體,它還可以指示是否使用分塊編碼接收到實(shí)體。
boolean isChunked();
//內(nèi)容的長(zhǎng)度
long getContentLength();
//獲取 Content-Type 標(biāo)頭。這是發(fā)送實(shí)體時(shí)應(yīng)使用的標(biāo)頭,或者與實(shí)體一起接收的標(biāo)頭。它可以包含一個(gè)字符集屬性。
Header getContentType();
//獲取 Content-Encoding 標(biāo)頭。這是發(fā)送實(shí)體時(shí)應(yīng)使用的標(biāo)頭,或者與實(shí)體一起接收的標(biāo)頭。修改內(nèi)容編碼的包裝實(shí)體應(yīng)相應(yīng)地調(diào)整此標(biāo)頭。
Header getContentEncoding();
//實(shí)體的內(nèi)容流??蒖epeatable實(shí)體應(yīng)為每次調(diào)用此方法創(chuàng)建一個(gè)新的InputStream實(shí)例,因此可以多次使用。不可repeatable的實(shí)體應(yīng)返回相同的InputStream實(shí)例,因此不得多次使用。
InputStream getContent() throws IOException, UnsupportedOperationException;
//實(shí)體內(nèi)容寫(xiě)入輸出流。重要提示:請(qǐng)注意,所有實(shí)體實(shí)現(xiàn)必須確保在此方法返回時(shí)正確釋放所有分配的資源。
void writeTo(OutputStream outStream) throws IOException;
//實(shí)體是否依賴于基礎(chǔ)流。直接從套接字讀取數(shù)據(jù)的流式實(shí)體應(yīng)返回true 。自包含實(shí)體應(yīng)返回false 。包裝實(shí)體應(yīng)將此調(diào)用委托給被包裝實(shí)體。
boolean isStreaming(); // don't expect an exception here
//自 4.1 版起已棄用。調(diào)用該方法表示不再需要該實(shí)體的內(nèi)容。由于此方法調(diào)用,所有實(shí)體實(shí)現(xiàn)都應(yīng)釋放所有分配的資源。
@Deprecated
void consumeContent() throws IOException;
}
AbstractHttpEntity:實(shí)體的抽象基類。為HttpEntity的流式和自包含實(shí)現(xiàn)提供常用屬性。
public abstract class AbstractHttpEntity implements HttpEntity {
protected static final int OUTPUT_BUFFER_SIZE = 4096;
protected Header contentType;
protected Header contentEncoding;
protected boolean chunked;
protected AbstractHttpEntity() {
super();
}
@Override
public Header getContentType() {
return this.contentType;
}
@Override
public Header getContentEncoding() {
return this.contentEncoding;
}
@Override
public boolean isChunked() {
return this.chunked;
}
public void setContentType(final Header contentType) {
this.contentType = contentType;
}
public void setContentType(final String ctString) {
Header h = null;
if (ctString != null) {
h = new BasicHeader(HTTP.CONTENT_TYPE, ctString);
}
setContentType(h);
}
public void setContentEncoding(final Header contentEncoding) {
this.contentEncoding = contentEncoding;
}
public void setContentEncoding(final String ceString) {
Header h = null;
if (ceString != null) {
h = new BasicHeader(HTTP.CONTENT_ENCODING, ceString);
}
setContentEncoding(h);
}
public void setChunked(final boolean b) {
this.chunked = b;
}
@Override
@Deprecated
public void consumeContent() throws IOException {
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append('[');
if (contentType != null) {
sb.append("Content-Type: ");
sb.append(contentType.getValue());
sb.append(',');
}
if (contentEncoding != null) {
sb.append("Content-Encoding: ");
sb.append(contentEncoding.getValue());
sb.append(',');
}
final long len = getContentLength();
if (len >= 0) {
sb.append("Content-Length: ");
sb.append(len);
sb.append(',');
}
sb.append("Chunked: ");
sb.append(chunked);
sb.append(']');
return sb.toString();
}
}
AbstractHttpEntity下常用實(shí)體
BasicHttpEntity:從InputStream獲取其內(nèi)容的通用流式、不可重復(fù)實(shí)體
ByteArrayEntity:一個(gè)自包含的、可重復(fù)的實(shí)體,它從字節(jié)數(shù)組中獲取其內(nèi)容。
EntityTemplate:將內(nèi)容生成過(guò)程委托給ContentProducer的實(shí)體。
FileEntity:從文件中獲取其內(nèi)容的自包含、可重復(fù)的實(shí)體。
InputStreamEntity:從InputStream獲取其內(nèi)容的流式、不可重復(fù)的實(shí)體。
SerializableEntity:從Serializable獲取其內(nèi)容的流式實(shí)體。從Serializable實(shí)例獲得的內(nèi)容可以選擇緩沖在字節(jié)數(shù)組中,以使實(shí)體自包含和可重復(fù)。
StringEntity:一個(gè)自包含、可重復(fù)的實(shí)體,從String獲取其內(nèi)容。
UrlEncodedFormEntity:由 url 編碼對(duì)列表組成的實(shí)體。這在發(fā)送 HTTP POST 請(qǐng)求時(shí)通常很有用。
HttpEntityWrapper:用于包裝實(shí)體的基類。保留一個(gè)wrappedEntity并將所有調(diào)用委托給它。包裝實(shí)體的實(shí)現(xiàn)可以從此類派生,并且只需要覆蓋那些不應(yīng)委托給包裝實(shí)體的方法。
public class HttpEntityWrapper implements HttpEntity {
protected HttpEntity wrappedEntity;
public HttpEntityWrapper(final HttpEntity wrappedEntity) {
super();
this.wrappedEntity = Args.notNull(wrappedEntity, "Wrapped entity");
}
@Override
public boolean isRepeatable() {
return wrappedEntity.isRepeatable();
}
@Override
public boolean isChunked() {
return wrappedEntity.isChunked();
}
@Override
public long getContentLength() {
return wrappedEntity.getContentLength();
}
@Override
public Header getContentType() {
return wrappedEntity.getContentType();
}
@Override
public Header getContentEncoding() {
return wrappedEntity.getContentEncoding();
}
@Override
public InputStream getContent()
throws IOException {
return wrappedEntity.getContent();
}
@Override
public void writeTo(final OutputStream outStream)
throws IOException {
wrappedEntity.writeTo(outStream);
}
@Override
public boolean isStreaming() {
return wrappedEntity.isStreaming();
}
@Override
@Deprecated
public void consumeContent() throws IOException {
wrappedEntity.consumeContent();
}
}
HttpEntityWrapper下常用實(shí)體
BufferedHttpEntity:必要時(shí)緩沖其內(nèi)容的包裝實(shí)體。緩沖實(shí)體始終是可重復(fù)的。如果被包裝的實(shí)體本身是可重復(fù)的,則調(diào)用被傳遞。如果包裝的實(shí)體不可重復(fù),則將內(nèi)容一次讀入緩沖區(qū)并根據(jù)需要從那里提供。
DecompressingEntity:用于解壓HttpEntity實(shí)現(xiàn)的通用基類,其子類有支持Deflate的DeflateDecompressingEntity和支持GZip的GzipDecompressingEntity
GzipCompressingEntity:writing時(shí)壓縮內(nèi)容的包裝實(shí)體。
ResponseEntityProxy:包含在響應(yīng)消息中的HttpEntity的包裝器類。
HttpClient發(fā)起請(qǐng)求
HTTP 請(qǐng)求執(zhí)行的基本類HttpClient
目前最常用的實(shí)現(xiàn)類的是CloseableHttpClient,以前的DefaultHttpClient在自4.3版本之后作廢了。
@Contract(threading = ThreadingBehavior.SAFE)
public abstract class CloseableHttpClient implements HttpClient, Closeable {
private final Log log = LogFactory.getLog(getClass());
protected abstract CloseableHttpResponse doExecute(HttpHost target, HttpRequest request,
HttpContext context) throws IOException, ClientProtocolException;
//使用默認(rèn)上下文執(zhí)行 HTTP 請(qǐng)求。
@Override
public CloseableHttpResponse execute(
final HttpHost target,
final HttpRequest request,
final HttpContext context) throws IOException, ClientProtocolException {
return doExecute(target, request, context);
}
@Override
public CloseableHttpResponse execute(
final HttpUriRequest request,
final HttpContext context) throws IOException, ClientProtocolException {
Args.notNull(request, "HTTP request");
return doExecute(determineTarget(request), request, context);
}
private static HttpHost determineTarget(final HttpUriRequest request) throws ClientProtocolException {
HttpHost target = null;
final URI requestURI = request.getURI();
if (requestURI.isAbsolute()) {
target = URIUtils.extractHost(requestURI);
if (target == null) {
throw new ClientProtocolException("URI does not specify a valid host name: "
+ requestURI);
}
}
return target;
}
@Override
public CloseableHttpResponse execute(
final HttpUriRequest request) throws IOException, ClientProtocolException {
return execute(request, (HttpContext) null);
}
@Override
public CloseableHttpResponse execute(
final HttpHost target,
final HttpRequest request) throws IOException, ClientProtocolException {
return doExecute(target, request, null);
}
@Override
public <T> T execute(final HttpUriRequest request,
final ResponseHandler<? extends T> responseHandler) throws IOException,
ClientProtocolException {
return execute(request, responseHandler, null);
}
@Override
public <T> T execute(final HttpUriRequest request,
final ResponseHandler<? extends T> responseHandler, final HttpContext context)
throws IOException, ClientProtocolException {
final HttpHost target = determineTarget(request);
return execute(target, request, responseHandler, context);
}
@Override
public <T> T execute(final HttpHost target, final HttpRequest request,
final ResponseHandler<? extends T> responseHandler) throws IOException,
ClientProtocolException {
return execute(target, request, responseHandler, null);
}
@Override
public <T> T execute(final HttpHost target, final HttpRequest request,
final ResponseHandler<? extends T> responseHandler, final HttpContext context)
throws IOException, ClientProtocolException {
Args.notNull(responseHandler, "Response handler");
final CloseableHttpResponse response = execute(target, request, context);
try {
final T result = responseHandler.handleResponse(response);
final HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
return result;
} catch (final ClientProtocolException t) {
// Try to salvage the underlying connection in case of a protocol exception
final HttpEntity entity = response.getEntity();
try {
EntityUtils.consume(entity);
} catch (final Exception t2) {
// Log this exception. The original exception is more
// important and will be thrown to the caller.
this.log.warn("Error consuming content after an exception.", t2);
}
throw t;
} finally {
response.close();
}
}
}
target(HttpHost):請(qǐng)求的目標(biāo)主機(jī)。如果實(shí)現(xiàn)仍然可以確定路由,例如到默認(rèn)目標(biāo)或通過(guò)檢查請(qǐng)求,則可以接受null 。
request:要執(zhí)行的請(qǐng)求,支持HttpRequest和HttpUriRequest
responseHandler(ResponseHandler):響應(yīng)處理程序
context(HttpContext):用于執(zhí)行的上下文,或null使用默認(rèn)上下文
HttpClients是CloseableHttpClient實(shí)例的工廠方法。
public class HttpClients {
private HttpClients() {
super();
}
//創(chuàng)建構(gòu)建器對(duì)象以構(gòu)建自定義CloseableHttpClient實(shí)例。
public static HttpClientBuilder custom() {
return HttpClientBuilder.create();
}
//使用默認(rèn)配置創(chuàng)建CloseableHttpClient實(shí)例。
public static CloseableHttpClient createDefault() {
return HttpClientBuilder.create().build();
}
//基于系統(tǒng)屬性創(chuàng)建具有默認(rèn)配置的CloseableHttpClient實(shí)例。
public static CloseableHttpClient createSystem() {
return HttpClientBuilder.create().useSystemProperties().build();
}
//創(chuàng)建實(shí)現(xiàn)最基本 HTTP 協(xié)議支持的CloseableHttpClient實(shí)例。
public static CloseableHttpClient createMinimal() {
return new MinimalHttpClient(new PoolingHttpClientConnectionManager());
}
//創(chuàng)建實(shí)現(xiàn)最基本 HTTP 協(xié)議支持的CloseableHttpClient實(shí)例。
public static CloseableHttpClient createMinimal(final HttpClientConnectionManager connManager) {
return new MinimalHttpClient(connManager);
}
}
HttpClient響應(yīng)
目前最常用的是CloseableHttpResponse
public interface CloseableHttpResponse extends HttpResponse, Closeable {
}
HttpResponse
public interface HttpResponse extends HttpMessage {
//獲取此響應(yīng)的狀態(tài)行??梢允褂胹etStatusLine方法之一設(shè)置狀態(tài)行,也可以在構(gòu)造函數(shù)中對(duì)其進(jìn)行初始化。
StatusLine getStatusLine();
//設(shè)置此響應(yīng)的狀態(tài)行。
void setStatusLine(StatusLine statusline);
//設(shè)置此響應(yīng)的狀態(tài)行。原因短語(yǔ)將根據(jù)當(dāng)前l(fā)ocale確定。
void setStatusLine(ProtocolVersion ver, int code);
void setStatusLine(ProtocolVersion ver, int code, String reason);
//使用新的狀態(tài)代碼更新此響應(yīng)的狀態(tài)行。
void setStatusCode(int code)
throws IllegalStateException;
//使用新的原因短語(yǔ)更新此響應(yīng)的狀態(tài)行。
void setReasonPhrase(String reason)
throws IllegalStateException;
//獲取此響應(yīng)的消息實(shí)體(如果有)。該實(shí)體是通過(guò)調(diào)用setEntity來(lái)提供的。
HttpEntity getEntity();
//將響應(yīng)實(shí)體與此響應(yīng)相關(guān)聯(lián)。
void setEntity(HttpEntity entity);
//更改此響應(yīng)的語(yǔ)言環(huán)境。
void setLocale(Locale loc);
}

HttpClient進(jìn)行POST請(qǐng)求例子:
private static String sendPOST(String url) throws IOException {
String result = "";
HttpPost post = new HttpPost(url);
List<NameValuePair> urlParameters = new ArrayList<>();
urlParameters.add(new BasicNameValuePair("username", "abc"));
urlParameters.add(new BasicNameValuePair("password", "123"));
post.setEntity(new UrlEncodedFormEntity(urlParameters));
try (CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(post)){
result = EntityUtils.toString(response.getEntity());
}
return result;
}
HttpURLConnection相關(guān)博客推薦
上傳文件:https://lsqingfeng.blog.csdn.net/article/details/90611686
下載文件:https://blog.csdn.net/WxQ92222/article/details/79896489
調(diào)用鏈路源碼分析可以參考:
https://blog.csdn.net/u012504392/article/details/109432686