1、HttpClient的最常用功能是execute()方法。執行一次execute()會包括了一次或多次request請求 - response響應事件。HttpClient會將request請求發送給目標服務器以取得response響應對象,也可有可能在執行失敗後拋出一個異常。
一個簡單的代碼如下:
CloseableHttpClienthttpclient = HttpClients.createDefault();
HttpGet httpget = newHttpGet("http://localhost/");
CloseableHttpResponse response = httpclient.execute(httpget);
try {
<...>
} finally {
response.close();
}
2、所有的Http request請求都包括了一個方法名、一個請求地址和一個HTTP協議版本號。HttpClient支持HTTP/1.1協議下所有的HTTP方法,包括:Get、HEAD、POST、PUT、DELETE、TRACE和OPTIONS。每一種方法都通過特定的類來實現,包括HttpGet、HttpHead、HttpPost、HttpPut、HttpDelete、HttpTrace和HttpOptions。
請求地址由一個URI(統一資源定位符)來描述。Http URI包括了協議、主機名、端口、地址、請求參數等。
例如:
HttpGet httpget = newHttpGet(
"http://www.google.com/search?hl=en&q=httpclient&btnG=Google+Search&aq=f&oq=");
HttpClient 提供了URIBuilder類來簡化請求地址的創建和修改,例如:
URI uri = newURIBuilder()
.setScheme("http")
.setHost("www.google.com")
.setPath("/search")
.setParameter("q","httpclient")
.setParameter("btnG","Google Search")
.setParameter("aq","f")
.setParameter("oq","")
.build();
HttpGet httpget = new HttpGet(uri);
System.out.println(httpget.getURI());
輸出:
http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq=
3、Httpresponse是服務器返回給客戶端的一段報文。報文的第一行包括了協議版本、數字狀態碼和文字描述。例如:
HttpResponse response= new BasicHttpResponse(HttpVersion.HTTP_1_1,
HttpStatus.SC_OK, "OK");
System.out.println(response.getProtocolVersion());
System.out.println(response.getStatusLine().getStatusCode());
System.out.println(response.getStatusLine().getReasonPhrase());
System.out.println(response.getStatusLine().toString());
4、一段Http報文包括了多個header描述屬性,包括內容長度、內容類型等等,HttpClient提供了查詢、刪除、處理header的方法,例如:
HttpResponse response= new BasicHttpResponse(HttpVersion.HTTP_1_1,
HttpStatus.SC_OK,"OK");
response.addHeader("Set-Cookie",
"c1=a; path=/;domain=localhost");
response.addHeader("Set-Cookie",
"c2=b; path=\"/\",c3=c; domain=\"localhost\"");
Header h1 = response.getFirstHeader("Set-Cookie");
System.out.println(h1);
Header h2 =response.getLastHeader("Set-Cookie");
System.out.println(h2);
Header[] hs =response.getHeaders("Set-Cookie");
System.out.println(hs.length);
輸出:
Set-Cookie: c1=a;path=/; domain=localhost
Set-Cookie: c2=b; path="/", c3=c; domain="localhost"
2
最有效率的做法是用HeaderIterator來獲得特定類型的所有header。
例如:
HttpResponse response= new BasicHttpResponse(HttpVersion.HTTP_1_1,
HttpStatus.SC_OK,"OK");
response.addHeader("Set-Cookie",
"c1=a; path=/;domain=localhost");
response.addHeader("Set-Cookie",
"c2=b; path=\"/\",c3=c; domain=\"localhost\"");
HeaderIterator it =response.headerIterator("Set-Cookie");
while (it.hasNext()){
System.out.println(it.next());
}
輸出:
Set-Cookie: c1=a;path=/; domain=localhost
Set-Cookie: c2=b; path="/", c3=c; domain="localhost"
5、HttpEntity 是Http request-reponse交互的報文內容。HttpClient區分了三種報文內容:
(1)流形式的報文內容,報文內容不可重複。
(2)獨立的報文內容,報文內容是可重複的。
(3)從其他報文內容中獲取的報文內容。
通過HttpEntity的getContent()可以獲得Java.io.Inputstream的輸入流,也可以通過HttpEntity的writeTo(OutputStream)寫入內容。
HttpEntity的getContentType()和getContentLength()方法可以獲取Content-Type和Content-Length的元數據,getContentEncoding()方法可以獲取編碼格式。
例如:
StringEntity myEntity= new StringEntity("important message",
ContentType.create("text/plain", "UTF-8"));
System.out.println(myEntity.getContentType());
System.out.println(myEntity.getContentLength());
System.out.println(EntityUtils.toString(myEntity));
System.out.println(EntityUtils.toByteArray(myEntity).length);
輸出:
Content-Type:text/plain; charset=utf-8
17
important message
17
讀取HttpEntity,例如:
CloseableHttpClienthttpclient = HttpClients.createDefault();
HttpGet httpget = newHttpGet("http://localhost/");
CloseableHttpResponse response = httpclient.execute(httpget);
try {
HttpEntity entity =response.getEntity();
if (entity != null) {
long len =entity.getContentLength();
if (len != -1 && len <2048) {
System.out.println(EntityUtils.toString(entity));
} else {
// Stream contentout
}
}
} finally {
response.close();
}
也可以生成報文內容
File file = newFile("somefile.txt");
FileEntity entity = new FileEntity(file,
ContentType.create("text/plain", "UTF-8"));
HttpPost httppost =newHttpPost("http://localhost/action.do");
httppost.setEntity(entity);
6、可以通過UrlEncodeFormEntity來提交表單,例如
List<NameValuePair>formparams = new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair("param1","value1"));
formparams.add(new BasicNameValuePair("param2","value2"));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams,Consts.UTF_8);
HttpPost httppost = newHttpPost("http://localhost/handler.do");
httppost.setEntity(entity);
7、可以採用ResponseHandler來簡化連接操作,例如
CloseableHttpClienthttpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("http://localhost/json");
ResponseHandler<MyJsonObject>rh = new ResponseHandler<MyJsonObject>() {
@Override
public JsonObjecthandleResponse(
final HttpResponse response)throws IOException {
StatusLine statusLine =response.getStatusLine();
HttpEntity entity =response.getEntity();
if (statusLine.getStatusCode()>= 300) {
throw newHttpResponseException(
statusLine.getStatusCode(),
statusLine.getReasonPhrase());
}
if (entity == null) {
throw newClientProtocolException("Response contains no content");
}
Gson gson = newGsonBuilder().create();
ContentType contentType =ContentType.getOrDefault(entity);
Charset charset =contentType.getCharset();
Reader reader = newInputStreamReader(entity.getContent(), charset);
return gson.fromJson(reader,MyJsonObject.class);
}
};
MyJsonObject myjson = client.execute(httpget, rh);
8、 httpClient不是線程安全的,所以如果不再使用的話,可以通過close()方法進行關閉,例如
CloseableHttpClienthttpclient = HttpClients.createDefault();
try {
<...>
} finally {
httpclient.close();
}
9、HttpContext可以作爲Http交互的上下文,是以java.util.Map存儲的對象。包括了HttpConnection、HttpHost、HttpRoute、HttpRequest等,可以通過HttpclientContext來定義上下文狀態。
HttpContext context =<...>
HttpClientContext clientContext =HttpClientContext.adapt(context);
HttpHost target = clientContext.getTargetHost();
HttpRequest request = clientContext.getRequest();
HttpResponse response = clientContext.getResponse();
RequestConfig config = clientContext.getRequestConfig();
10、如果要實現重試機制,可以採用HttpRequestRetryHandler接口來實現。例如:
HttpRequestRetryHandlermyRetryHandler = new HttpRequestRetryHandler() {
public booleanretryRequest(
IOExceptionexception,
intexecutionCount,
HttpContext context){
if (executionCount >= 5){
// Do not retry if over maxretry count
return false;
}
if (exception instanceofInterruptedIOException) {
// Timeout
return false;
}
if (exception instanceofUnknownHostException) {
// Unknown host
return false;
}
if (exception instanceofConnectTimeoutException) {
// Connectionrefused
return false;
}
if (exception instanceofSSLException) {
// SSL handshakeexception
return false;
}
HttpClientContext clientContext =HttpClientContext.adapt(context);
HttpRequest request =clientContext.getRequest();
boolean idempotent = !(requestinstanceof HttpEntityEnclosingRequest);
if (idempotent) {
// Retry if the request isconsidered idempotent
return true;
}
return false;
}
};
CloseableHttpClient httpclient = HttpClients.custom()
.setRetryHandler(myRetryHandler)
.build();
11、重定向處理,例如:
CloseableHttpClienthttpclient = HttpClients.createDefault();
HttpClientContext context = HttpClientContext.create();
HttpGet httpget = newHttpGet("http://localhost:8080/");
CloseableHttpResponse response = httpclient.execute(httpget, context);
try {
HttpHost target =context.getTargetHost();
List<URI> redirectLocations =context.getRedirectLocations();
URI location =URIUtils.resolve(httpget.getURI(), target, redirectLocations);
System.out.println("Final HTTPlocation: " + location.toASCIIString());
// Expected to be an absoluteURI
} finally {
response.close();
}