客戶端http協(xié)議傳輸類庫拐叉。HttpClient被用來發(fā)送和接受Http消息理郑。HttpClient不會(huì)處理Http消息的內(nèi)容,不會(huì)進(jìn)行Javascript解析,不會(huì)關(guān)心ContentType病毡,如果沒有明確設(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í)行過程沒有施加任何限制或特定細(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;
}
}
無需實(shí)體入?yún)⒌恼?qǐng)求可以直接繼承HttpRequestBase
,官方HttpGet/HttpHead/HttpOptions/HttpTrace均不支持實(shí)體入?yún)⒌罚瑢?shí)在有需要可以自行重寫枷邪,直接繼承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)容的長度
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)容流羞秤「淄校可Repeatable實(shí)體應(yīng)為每次調(diào)用此方法創(chuàng)建一個(gè)新的InputStream實(shí)例,因此可以多次使用瘾蛋。不可repeatable的實(shí)體應(yīng)返回相同的InputStream實(shí)例俐镐,因此不得多次使用。
InputStream getContent() throws IOException, UnsupportedOperationException;
//實(shí)體內(nèi)容寫入輸出流哺哼。重要提示:請(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)容生成過程委托給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)或通過檢查請(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)行雅镊〗罄祝可以使用setStatusLine方法之一設(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)行。原因短語將根據(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īng)的狀態(tài)行。
void setReasonPhrase(String reason)
throws IllegalStateException;
//獲取此響應(yīng)的消息實(shí)體(如果有)征唬。該實(shí)體是通過調(diào)用setEntity來提供的捌显。
HttpEntity getEntity();
//將響應(yīng)實(shí)體與此響應(yīng)相關(guān)聯(lián)。
void setEntity(HttpEntity entity);
//更改此響應(yīng)的語言環(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