欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

提升網(wǎng)絡(luò)請(qǐng)求穩(wěn)定性HttpClient的重試機(jī)制深入理解

 更新時(shí)間:2023年10月13日 11:08:34   作者:codecraft  
這篇文章主要為大家介紹了提升網(wǎng)絡(luò)請(qǐng)求穩(wěn)定性HttpClient的重試機(jī)制深入理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

本文主要研究一下HttpClient的重試機(jī)制

HttpRequestRetryHandler

org/apache/http/client/HttpRequestRetryHandler.java

public interface HttpRequestRetryHandler {
    /**
     * Determines if a method should be retried after an IOException
     * occurs during execution.
     *
     * @param exception the exception that occurred
     * @param executionCount the number of times this method has been
     * unsuccessfully executed
     * @param context the context for the request execution
     *
     * @return {@code true} if the method should be retried, {@code false}
     * otherwise
     */
    boolean retryRequest(IOException exception, int executionCount, HttpContext context);
}
HttpRequestRetryHandler接口定義了retryRequest方法,它接收IOException、executionCount及context,然后判斷是否可以重試

DefaultHttpRequestRetryHandler

org/apache/http/impl/client/DefaultHttpRequestRetryHandler.java

@Contract(threading = ThreadingBehavior.IMMUTABLE)
public class DefaultHttpRequestRetryHandler implements HttpRequestRetryHandler {
    public static final DefaultHttpRequestRetryHandler INSTANCE = new DefaultHttpRequestRetryHandler();
    /** the number of times a method will be retried */
    private final int retryCount;
    /** Whether or not methods that have successfully sent their request will be retried */
    private final boolean requestSentRetryEnabled;
    private final Set<Class<? extends IOException>> nonRetriableClasses;
    /**
     * Create the request retry handler using the specified IOException classes
     *
     * @param retryCount how many times to retry; 0 means no retries
     * @param requestSentRetryEnabled true if it's OK to retry requests that have been sent
     * @param clazzes the IOException types that should not be retried
     * @since 4.3
     */
    protected DefaultHttpRequestRetryHandler(
            final int retryCount,
            final boolean requestSentRetryEnabled,
            final Collection<Class<? extends IOException>> clazzes) {
        super();
        this.retryCount = retryCount;
        this.requestSentRetryEnabled = requestSentRetryEnabled;
        this.nonRetriableClasses = new HashSet<Class<? extends IOException>>();
        for (final Class<? extends IOException> clazz: clazzes) {
            this.nonRetriableClasses.add(clazz);
        }
    }
    /**
     * Create the request retry handler using the following list of
     * non-retriable IOException classes: 
     * <ul>
     * <li>InterruptedIOException</li>
     * <li>UnknownHostException</li>
     * <li>ConnectException</li>
     * <li>SSLException</li>
     * </ul>
     * @param retryCount how many times to retry; 0 means no retries
     * @param requestSentRetryEnabled true if it's OK to retry non-idempotent requests that have been sent
     */
    @SuppressWarnings("unchecked")
    public DefaultHttpRequestRetryHandler(final int retryCount, final boolean requestSentRetryEnabled) {
        this(retryCount, requestSentRetryEnabled, Arrays.asList(
                InterruptedIOException.class,
                UnknownHostException.class,
                ConnectException.class,
                SSLException.class));
    }
    /**
     * Create the request retry handler with a retry count of 3, requestSentRetryEnabled false
     * and using the following list of non-retriable IOException classes: 
     * <ul>
     * <li>InterruptedIOException</li>
     * <li>UnknownHostException</li>
     * <li>ConnectException</li>
     * <li>SSLException</li>
     * </ul>
     */
    public DefaultHttpRequestRetryHandler() {
        this(3, false);
    }
    /**
     * Used {@code retryCount} and {@code requestSentRetryEnabled} to determine
     * if the given method should be retried.
     */
    @Override
    public boolean retryRequest(
            final IOException exception,
            final int executionCount,
            final HttpContext context) {
        Args.notNull(exception, "Exception parameter");
        Args.notNull(context, "HTTP context");
        if (executionCount > this.retryCount) {
            // Do not retry if over max retry count
            return false;
        }
        if (this.nonRetriableClasses.contains(exception.getClass())) {
            return false;
        }
        for (final Class<? extends IOException> rejectException : this.nonRetriableClasses) {
            if (rejectException.isInstance(exception)) {
                return false;
            }
        }
        final HttpClientContext clientContext = HttpClientContext.adapt(context);
        final HttpRequest request = clientContext.getRequest();
        if(requestIsAborted(request)){
            return false;
        }
        if (handleAsIdempotent(request)) {
            // Retry if the request is considered idempotent
            return true;
        }
        if (!clientContext.isRequestSent() || this.requestSentRetryEnabled) {
            // Retry if the request has not been sent fully or
            // if it's OK to retry methods that have been sent
            return true;
        }
        // otherwise do not retry
        return false;
    }
    /**
     * @return {@code true} if this handler will retry methods that have
     * successfully sent their request, {@code false} otherwise
     */
    public boolean isRequestSentRetryEnabled() {
        return requestSentRetryEnabled;
    }
    /**
     * @return the maximum number of times a method will be retried
     */
    public int getRetryCount() {
        return retryCount;
    }
    /**
     * @since 4.2
     */
    protected boolean handleAsIdempotent(final HttpRequest request) {
        return !(request instanceof HttpEntityEnclosingRequest);
    }
    /**
     * @since 4.2
     *
     * @deprecated (4.3)
     */
    @Deprecated
    protected boolean requestIsAborted(final HttpRequest request) {
        HttpRequest req = request;
        if (request instanceof RequestWrapper) { // does not forward request to original
            req = ((RequestWrapper) request).getOriginal();
        }
        return (req instanceof HttpUriRequest && ((HttpUriRequest)req).isAborted());
    }
}
DefaultHttpRequestRetryHandler實(shí)現(xiàn)了HttpRequestRetryHandler接口,其無(wú)參構(gòu)造器默認(rèn)將InterruptedIOException、UnknownHostException、ConnectException、SSLException設(shè)定為不重試的異常,默認(rèn)retryCount為3,requestSentRetryEnabled為false;其retryRequest方法先判斷executionCount是否超出retryCount,接著判斷異常類(lèi)型是否是不重試的異常類(lèi)型,若request為aborted則返回false,若request非HttpEntityEnclosingRequest則表示冪等請(qǐng)求,返回true,若請(qǐng)求未完全發(fā)送則返回true,其余的默認(rèn)返回false。

RetryExec

org/apache/http/impl/execchain/RetryExec.java

@Contract(threading = ThreadingBehavior.IMMUTABLE_CONDITIONAL)
public class RetryExec implements ClientExecChain {
    private final Log log = LogFactory.getLog(getClass());
    private final ClientExecChain requestExecutor;
    private final HttpRequestRetryHandler retryHandler;
    public RetryExec(
            final ClientExecChain requestExecutor,
            final HttpRequestRetryHandler retryHandler) {
        Args.notNull(requestExecutor, "HTTP request executor");
        Args.notNull(retryHandler, "HTTP request retry handler");
        this.requestExecutor = requestExecutor;
        this.retryHandler = retryHandler;
    }
    @Override
    public CloseableHttpResponse execute(
            final HttpRoute route,
            final HttpRequestWrapper request,
            final HttpClientContext context,
            final HttpExecutionAware execAware) throws IOException, HttpException {
        Args.notNull(route, "HTTP route");
        Args.notNull(request, "HTTP request");
        Args.notNull(context, "HTTP context");
        final Header[] origheaders = request.getAllHeaders();
        for (int execCount = 1;; execCount++) {
            try {
                return this.requestExecutor.execute(route, request, context, execAware);
            } catch (final IOException ex) {
                if (execAware != null && execAware.isAborted()) {
                    this.log.debug("Request has been aborted");
                    throw ex;
                }
                if (retryHandler.retryRequest(ex, execCount, context)) {
                    if (this.log.isInfoEnabled()) {
                        this.log.info("I/O exception ("+ ex.getClass().getName() +
                                ") caught when processing request to "
                                + route +
                                ": "
                                + ex.getMessage());
                    }
                    if (this.log.isDebugEnabled()) {
                        this.log.debug(ex.getMessage(), ex);
                    }
                    if (!RequestEntityProxy.isRepeatable(request)) {
                        this.log.debug("Cannot retry non-repeatable request");
                        throw new NonRepeatableRequestException("Cannot retry request " +
                                "with a non-repeatable request entity", ex);
                    }
                    request.setHeaders(origheaders);
                    if (this.log.isInfoEnabled()) {
                        this.log.info("Retrying request to " + route);
                    }
                } else {
                    if (ex instanceof NoHttpResponseException) {
                        final NoHttpResponseException updatedex = new NoHttpResponseException(
                                route.getTargetHost().toHostString() + " failed to respond");
                        updatedex.setStackTrace(ex.getStackTrace());
                        throw updatedex;
                    }
                    throw ex;
                }
            }
        }
    }
}
RetryExec實(shí)現(xiàn)了ClientExecChain接口,其execute方法會(huì)循環(huán)執(zhí)行requestExecutor.execute,它c(diǎn)atch了IOException,對(duì)于retryHandler.retryRequest(ex, execCount, context)返回true的,會(huì)在通過(guò)RequestEntityProxy.isRepeatable(request)判斷一下是否是可重復(fù)讀取的request,不是則拋出NonRepeatableRequestException;對(duì)于retryHandler.retryRequest返回false的則針對(duì)NoHttpResponseException重新包裝一下,將targetHost體現(xiàn)在message里頭然后重新拋出

HttpEntityEnclosingRequest

org/apache/http/HttpEntityEnclosingRequest.java

public interface HttpEntityEnclosingRequest extends HttpRequest {
    /**
     * Tells if this request should use the expect-continue handshake.
     * The expect continue handshake gives the server a chance to decide
     * whether to accept the entity enclosing request before the possibly
     * lengthy entity is sent across the wire.
     * @return true if the expect continue handshake should be used, false if
     * not.
     */
    boolean expectContinue();
    /**
     * Associates the entity with this request.
     *
     * @param entity the entity to send.
     */
    void setEntity(HttpEntity entity);
    /**
     * Returns the entity associated with this request.
     *
     * @return entity
     */
    HttpEntity getEntity();
}
HttpEntityEnclosingRequest定義了getEntity、setEntity、expectContinue方法,它的子類(lèi)有HttpPut、HttpPost、HttpPatch、HttpDelete等

RequestEntityProxy.isRepeatable

org/apache/http/impl/execchain/RequestEntityProxy.java

class RequestEntityProxy implements HttpEntity  {
    private final HttpEntity original;
    private boolean consumed = false;
    public boolean isConsumed() {
        return consumed;
    }
    static boolean isRepeatable(final HttpRequest request) {
        if (request instanceof HttpEntityEnclosingRequest) {
            final HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
            if (entity != null) {
                if (isEnhanced(entity)) {
                    final RequestEntityProxy proxy = (RequestEntityProxy) entity;
                    if (!proxy.isConsumed()) {
                        return true;
                    }
                }
                return entity.isRepeatable();
            }
        }
        return true;
    }
}
RequestEntityProxy提供了靜態(tài)方法isRepeatable用于判斷該request的entity是否可以重復(fù)讀取,對(duì)于非HttpEntityEnclosingRequest的返回true,是HttpEntityEnclosingRequest類(lèi)型的話則判斷entity.isRepeatable(),若entity是RequestEntityProxy類(lèi)型的,則通過(guò)RequestEntityProxy.isConsumed來(lái)判斷

entity.isRepeatable()

public interface HttpEntity {
    /**
     * Tells if the entity is capable of producing its data more than once.
     * A repeatable entity's getContent() and writeTo(OutputStream) methods
     * can be called more than once whereas a non-repeatable entity's can not.
     * @return true if the entity is repeatable, false otherwise.
     */
    boolean isRepeatable();
    //......
}
HttpEntity接口定義了isRepeatable方法,用于表示entity的content及OutputStream是否可以讀寫(xiě)多次。其實(shí)現(xiàn)類(lèi)里頭,BufferedHttpEntity、ByteArrayEntity、EntityTemplate、FileEntity、SerializableEntity、StringEntity為true,BasicHttpEntity、InputStreamEntity、StreamingHttpEntity為false

小結(jié)

HttpRequestRetryHandler接口定義了retryRequest方法,它接收IOException、executionCount及context,然后判斷是否可以重試

DefaultHttpRequestRetryHandler實(shí)現(xiàn)了HttpRequestRetryHandler接口,其無(wú)參構(gòu)造器默認(rèn)將InterruptedIOException、UnknownHostException、ConnectException、SSLException設(shè)定為不重試的異常,默認(rèn)retryCount為3,requestSentRetryEnabled為false;其retryRequest方法先判斷executionCount是否超出retryCount,接著判斷異常類(lèi)型是否是不重試的異常類(lèi)型,若request為aborted則返回false,若request非HttpEntityEnclosingRequest則表示冪等請(qǐng)求,返回true,若請(qǐng)求未完全發(fā)送則返回true,其余的默認(rèn)返回false。

RetryExec實(shí)現(xiàn)了ClientExecChain接口,其execute方法會(huì)循環(huán)執(zhí)行requestExecutor.execute,它c(diǎn)atch了IOException,對(duì)于retryHandler.retryRequest(ex, execCount, context)返回true的,會(huì)在通過(guò)RequestEntityProxy.isRepeatable(request)判斷一下是否是可重復(fù)讀取的request,不是則拋出NonRepeatableRequestException

DefaultHttpRequestRetryHandler針對(duì)不是冪等請(qǐng)求的HttpEntityEnclosingRequest類(lèi)型(HttpPut、HttpPost、HttpPatch、HttpDelete),不會(huì)重試;若retryHandler.retryRequest返回可以重試,RetryExec還有一個(gè)repeatable的判斷,BufferedHttpEntity、ByteArrayEntity、EntityTemplate、FileEntity、SerializableEntity、StringEntity為true,BasicHttpEntity、InputStreamEntity、StreamingHttpEntity為false

以上就是提升網(wǎng)絡(luò)請(qǐng)求穩(wěn)定性HttpClient的重試機(jī)制深入理解的詳細(xì)內(nèi)容,更多關(guān)于HttpClient重試機(jī)制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解SpringBoot開(kāi)發(fā)案例之整合定時(shí)任務(wù)(Scheduled)

    詳解SpringBoot開(kāi)發(fā)案例之整合定時(shí)任務(wù)(Scheduled)

    本篇文章主要介紹了詳解SpringBoot開(kāi)發(fā)案例之整合定時(shí)任務(wù)(Scheduled),具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-07-07
  • mybatisplus使用xml的示例詳解

    mybatisplus使用xml的示例詳解

    這篇文章主要介紹了mybatisplus使用xml,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • 使用Java代碼進(jìn)行因數(shù)分解和求最小公倍數(shù)的示例

    使用Java代碼進(jìn)行因數(shù)分解和求最小公倍數(shù)的示例

    這篇文章主要介紹了使用Java代碼進(jìn)行因數(shù)分解和求最小公倍數(shù)的示例,都是基于最基礎(chǔ)的算法原理實(shí)現(xiàn),需要的朋友可以參考下
    2015-11-11
  • Spring Boot與前端配合與Idea配置部署操作過(guò)程

    Spring Boot與前端配合與Idea配置部署操作過(guò)程

    這篇文章主要介紹了Spring Boot與前端配合與Idea配置部署的操作過(guò)程,本文圖文并茂給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2018-02-02
  • Java編程實(shí)現(xiàn)遍歷兩個(gè)MAC地址之間所有MAC的方法

    Java編程實(shí)現(xiàn)遍歷兩個(gè)MAC地址之間所有MAC的方法

    這篇文章主要介紹了Java編程實(shí)現(xiàn)遍歷兩個(gè)MAC地址之間所有MAC的方法,涉及Java針對(duì)MAC的遍歷獲取與字符串轉(zhuǎn)換相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-11-11
  • 淺談Java ThreadPoolExecutor的使用

    淺談Java ThreadPoolExecutor的使用

    今天我們來(lái)學(xué)習(xí)一下Java ThreadPoolExecutor的使用,文中有非常詳細(xì)的介紹及代碼示例,對(duì)正在學(xué)習(xí)Java的小伙伴們有很大的幫助,需要的朋友可以參考下
    2021-05-05
  • 一篇文章讓你學(xué)會(huì)Java的輸入與輸出

    一篇文章讓你學(xué)會(huì)Java的輸入與輸出

    這篇文章主要介紹了Java輸入與輸出的相關(guān)資料,包括使用System.out.println()、System.out.printf()和System.out.print()進(jìn)行輸出,以及使用Scanner類(lèi)和System.in.read()方法進(jìn)行輸入,需要的朋友可以參考下
    2025-03-03
  • Springboot以Repository方式整合Redis的方法

    Springboot以Repository方式整合Redis的方法

    這篇文章主要介紹了Springboot以Repository方式整合Redis的方法,本文通過(guò)圖文并茂實(shí)例詳解給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • java實(shí)現(xiàn)屏蔽詞功能

    java實(shí)現(xiàn)屏蔽詞功能

    這篇文章主要介紹了java實(shí)現(xiàn)屏蔽詞功能,類(lèi)似貼吧里面屏蔽各種用戶的發(fā)帖內(nèi)容,感興趣的小伙伴們可以參考一下
    2015-12-12
  • 簡(jiǎn)單了解JAVA內(nèi)存區(qū)域效果知識(shí)

    簡(jiǎn)單了解JAVA內(nèi)存區(qū)域效果知識(shí)

    這篇文章主要介紹了簡(jiǎn)單了解JAVA內(nèi)存區(qū)域效果知識(shí),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10

最新評(píng)論