標籤:text finally prot body tom socket lang span context
在進行http請求時,難免會遇到請求失敗的情況,失敗後需要重新請求,嘗試再次擷取資料。
Apache的HttpClient提供了異常重試機制,在該機制中,我們可以很靈活的定義在哪些異常情況下進行重試。
重試前提
被請求的方法必須是等冪的:就是多次請求服務端結果應該是準確且一致的。
適合的方法:比如根據ID,修改人員姓名,無論請求多次結果都是一樣,這就是等冪。 不適合的方法:比如減少帳號50元,多次請求將多次扣減。實現方式想要實現異常重試,需要實現它提供的一個介面 HttpRequestRetryHandler ,並實現 retryRequest 方法。然後set到HttpClient中。該httpClient就具備了重試機制。 HttpClient自身提供了 StandardHttpRequestRetryHandler 和 DefaultHttpRequestRetryHandler 兩個實作類別。 DefaultHttpRequestRetryHandler 繼承自 DefaultHttpRequestRetryHandler , StandardHttpRequestRetryHandler 預設幾個方法為等冪,如PUT、GET、HEAD等除POST外的方法,如果自訂可以參考它的實現方式。 代碼如下:
1 import java.io.IOException; 2 import java.io.InterruptedIOException; 3 import java.net.ConnectException; 4 import java.net.UnknownHostException; 5 6 import javax.net.ssl.SSLException; 7 8 import org.apache.commons.lang3.ObjectUtils; 9 import org.apache.commons.lang3.StringUtils; 10 import org.apache.http.Consts; 11 import org.apache.http.HttpEntityEnclosingRequest; 12 import org.apache.http.HttpRequest; 13 import org.apache.http.HttpStatus; 14 import org.apache.http.ParseException; 15 import org.apache.http.client.HttpRequestRetryHandler; 16 import org.apache.http.client.config.RequestConfig; 17 import org.apache.http.client.methods.CloseableHttpResponse; 18 import org.apache.http.client.methods.HttpPost; 19 import org.apache.http.client.protocol.HttpClientContext; 20 import org.apache.http.entity.ContentType; 21 import org.apache.http.entity.StringEntity; 22 import org.apache.http.impl.client.CloseableHttpClient; 23 import org.apache.http.impl.client.HttpClients; 24 import org.apache.http.protocol.HttpContext; 25 import org.apache.http.util.EntityUtils; 26 27 /** 28 * @author 29 * 29 * @date 2017年5月18日 上午9:17:30 30 * 31 * @Description 32 */ 33 public class HttpPostUtils { 34 /** 35 * 36 * @param uri 37 * the request address 38 * @param json 39 * the request data that must be a JSON string 40 * @param retryCount 41 * the number of times this method has been unsuccessfully 42 * executed 43 * @param connectTimeout 44 * the timeout in milliseconds until a connection is established 45 * @param connectionRequestTimeout 46 * the timeout in milliseconds used when requesting a connection 47 * from the connection manager 48 * @param socketTimeout 49 * the socket timeout in milliseconds, which is the timeout for 50 * waiting for data or, put differently, a maximum period 51 * inactivity between two consecutive data packets 52 * @return null when method parameter is null, "", " " 53 * @throws IOException 54 * if HTTP connection can not opened or closed successfully 55 * @throws ParseException 56 * if response data can not be parsed successfully 57 */ 58 public String retryPostJson(String uri, String json, int retryCount, int connectTimeout, 59 int connectionRequestTimeout, int socketTimeout) throws IOException, ParseException { 60 if (StringUtils.isAnyBlank(uri, json)) { 61 return null; 62 } 63 64 HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() { 65 66 @Override 67 public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { 68 if (executionCount > retryCount) { 69 // Do not retry if over max retry count 70 return false; 71 } 72 if (exception instanceof InterruptedIOException) { 73 // An input or output transfer has been terminated 74 return false; 75 } 76 if (exception instanceof UnknownHostException) { 77 // Unknown host 修改代碼讓不識別主機時重試,實際業務當不識別的時候不應該重試,再次為了示範重試過程,執行會顯示retryCount次下面的輸出 78 System.out.println("不識別主機重試"); return true; 79 } 80 if (exception instanceof ConnectException) { 81 // Connection refused 82 return false; 83 } 84 if (exception instanceof SSLException) { 85 // SSL handshake exception 86 return false; 87 } 88 HttpClientContext clientContext = HttpClientContext.adapt(context); 89 HttpRequest request = clientContext.getRequest(); 90 boolean idempotent = !(request instanceof HttpEntityEnclosingRequest); 91 if (idempotent) { 92 // Retry if the request is considered idempotent 93 return true; 94 } 95 return false; 96 } 97 }; 98 99 CloseableHttpClient client = HttpClients.custom().setRetryHandler(httpRequestRetryHandler).build();100 HttpPost post = new HttpPost(uri);101 // Create request data102 StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);103 // Set request body104 post.setEntity(entity);105 106 RequestConfig config = RequestConfig.custom().setConnectTimeout(connectTimeout)107 .setConnectionRequestTimeout(connectionRequestTimeout).setSocketTimeout(socketTimeout).build();108 post.setConfig(config);109 // Response content110 String responseContent = null;111 CloseableHttpResponse response = null;112 try {113 response = client.execute(post, HttpClientContext.create());114 if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {115 responseContent = EntityUtils.toString(response.getEntity(), Consts.UTF_8.name());116 }117 } finally {118 if (ObjectUtils.anyNotNull(response)) {119 response.close();120 }121 if (ObjectUtils.anyNotNull(client)) {122 client.close();123 }124 }125 return responseContent;126 }
轉載自:http://www.cnblogs.com/wuxiaofeng/p/6879292.html,感謝分享。
使用Apache HttpClient 4.x進行異常重試