乐趣区

聊聊nacos-client的ServerHttpAgent

本文主要研究一下 nacos client 的 ServerHttpAgent

HttpAgent

nacos-1.1.3/client/src/main/java/com/alibaba/nacos/client/config/http/HttpAgent.java

public interface HttpAgent {
    /**
     * start to get nacos ip list
     * @return Nothing.
     * @throws NacosException on get ip list error.
     */
    void start() throws NacosException;

    /**
     * invoke http get method
     * @param path http path
     * @param headers http headers
     * @param paramValues http paramValues http
     * @param encoding http encode
     * @param readTimeoutMs http timeout
     * @return HttpResult http response
     * @throws IOException If an input or output exception occurred
     */

    HttpResult httpGet(String path, List<String> headers, List<String> paramValues, String encoding, long readTimeoutMs) throws IOException;

    /**
     * invoke http post method
     * @param path http path
     * @param headers http headers
     * @param paramValues http paramValues http
     * @param encoding http encode
     * @param readTimeoutMs http timeout
     * @return HttpResult http response
     * @throws IOException If an input or output exception occurred
     */
    HttpResult httpPost(String path, List<String> headers, List<String> paramValues, String encoding, long readTimeoutMs) throws IOException;

    /**
     * invoke http delete method
     * @param path http path
     * @param headers http headers
     * @param paramValues http paramValues http
     * @param encoding http encode
     * @param readTimeoutMs http timeout
     * @return HttpResult http response
     * @throws IOException If an input or output exception occurred
     */
    HttpResult httpDelete(String path, List<String> headers, List<String> paramValues, String encoding, long readTimeoutMs) throws IOException;

    /**
     * get name
     * @return String
     */
    String getName();

    /**
     * get namespace
     * @return String
     */
    String getNamespace();

    /**
     * get tenant
     * @return String
     */
    String getTenant();

    /**
     * get encode
     * @return String
     */
    String getEncode();}
  • HttpAgent 定义了 start、httpGet、httpPost、httpDelete、getName、getNamespace、getTenant、getEncode 方法

ServerHttpAgent

nacos-1.1.3/client/src/main/java/com/alibaba/nacos/client/config/http/ServerHttpAgent.java

public class ServerHttpAgent implements HttpAgent {private static final Logger LOGGER = LogUtils.logger(ServerHttpAgent.class);

    /**
     * @param path          相对于 web 应用根,以 / 开头
     * @param headers
     * @param paramValues
     * @param encoding
     * @param readTimeoutMs
     * @return
     * @throws IOException
     */
    @Override
    public HttpResult httpGet(String path, List<String> headers, List<String> paramValues, String encoding,
                              long readTimeoutMs) throws IOException {final long endTime = System.currentTimeMillis() + readTimeoutMs;
        final boolean isSSL = false;

        String currentServerAddr = serverListMgr.getCurrentServerAddr();
        int maxRetry = this.maxRetry;

        do {
            try {List<String> newHeaders = getSpasHeaders(paramValues);
                if (headers != null) {newHeaders.addAll(headers);
                }
                HttpResult result = HttpSimpleClient.httpGet(getUrl(currentServerAddr, path), newHeaders, paramValues, encoding,
                    readTimeoutMs, isSSL);
                if (result.code == HttpURLConnection.HTTP_INTERNAL_ERROR
                    || result.code == HttpURLConnection.HTTP_BAD_GATEWAY
                    || result.code == HttpURLConnection.HTTP_UNAVAILABLE) {LOGGER.error("[NACOS ConnectException] currentServerAddr: {}, httpCode: {}",
                        serverListMgr.getCurrentServerAddr(), result.code);
                } else {
                    // Update the currently available server addr
                    serverListMgr.updateCurrentServerAddr(currentServerAddr);
                    return result;
                }
            } catch (ConnectException ce) {LOGGER.error("[NACOS ConnectException httpGet] currentServerAddr:{}, err : {}", serverListMgr.getCurrentServerAddr(), ce.getMessage());
            } catch (SocketTimeoutException stoe) {LOGGER.error("[NACOS SocketTimeoutException httpGet] currentServerAddr:{},err : {}", serverListMgr.getCurrentServerAddr(), stoe.getMessage());
            } catch (IOException ioe) {LOGGER.error("[NACOS IOException httpGet] currentServerAddr:" + serverListMgr.getCurrentServerAddr(), ioe);
                throw ioe;
            }

            if (serverListMgr.getIterator().hasNext()) {currentServerAddr = serverListMgr.getIterator().next();} else {
                maxRetry --;
                if (maxRetry < 0) {throw new ConnectException("[NACOS HTTP-GET] The maximum number of tolerable server reconnection errors has been reached");
                }
                serverListMgr.refreshCurrentServerAddr();}

        } while (System.currentTimeMillis() <= endTime);

        LOGGER.error("no available server");
        throw new ConnectException("no available server");
    }

    @Override
    public HttpResult httpPost(String path, List<String> headers, List<String> paramValues, String encoding,
                               long readTimeoutMs) throws IOException {final long endTime = System.currentTimeMillis() + readTimeoutMs;
        boolean isSSL = false;

        String currentServerAddr = serverListMgr.getCurrentServerAddr();
        int maxRetry = this.maxRetry;

        do {

            try {List<String> newHeaders = getSpasHeaders(paramValues);
                if (headers != null) {newHeaders.addAll(headers);
                }

                HttpResult result = HttpSimpleClient.httpPost(getUrl(currentServerAddr, path), newHeaders, paramValues, encoding,
                    readTimeoutMs, isSSL);
                if (result.code == HttpURLConnection.HTTP_INTERNAL_ERROR
                    || result.code == HttpURLConnection.HTTP_BAD_GATEWAY
                    || result.code == HttpURLConnection.HTTP_UNAVAILABLE) {LOGGER.error("[NACOS ConnectException] currentServerAddr: {}, httpCode: {}",
                        currentServerAddr, result.code);
                } else {
                    // Update the currently available server addr
                    serverListMgr.updateCurrentServerAddr(currentServerAddr);
                    return result;
                }
            } catch (ConnectException ce) {LOGGER.error("[NACOS ConnectException httpPost] currentServerAddr: {}, err : {}", currentServerAddr, ce.getMessage());
            } catch (SocketTimeoutException stoe) {LOGGER.error("[NACOS SocketTimeoutException httpPost] currentServerAddr: {},err : {}", currentServerAddr, stoe.getMessage());
            } catch (IOException ioe) {LOGGER.error("[NACOS IOException httpPost] currentServerAddr:" + currentServerAddr, ioe);
                throw ioe;
            }

            if (serverListMgr.getIterator().hasNext()) {currentServerAddr = serverListMgr.getIterator().next();} else {
                maxRetry --;
                if (maxRetry < 0) {throw new ConnectException("[NACOS HTTP-POST] The maximum number of tolerable server reconnection errors has been reached");
                }
                serverListMgr.refreshCurrentServerAddr();}

        } while (System.currentTimeMillis() <= endTime);

        LOGGER.error("no available server, currentServerAddr : {}", currentServerAddr);
        throw new ConnectException("no available server, currentServerAddr :" + currentServerAddr);
    }

    //......
}
  • ServerHttpAgent 实现了 HttpAgent 接口,其 httpGet、httpPost、httpDelete 方法的结构大体相同,都是以 do while 做循环,循环条件为距离开始执行时间不超过 readTimeoutMs
  • 循环开始之前会通过 serverListMgr.getCurrentServerAddr() 方法获取 currentServerAddr,循环体内则通过 HttpSimpleClient 的相应方法执行请求,如果返回的 HTTP Code 为 HTTP_INTERNAL_ERROR、HTTP_BAD_GATEWAY、HTTP_UNAVAILABLE 则打印 error 日志,否则执行 serverListMgr.updateCurrentServerAddr(currentServerAddr),然后返回
  • 如果出现异常或者没有提前返回,则判断 serverListMgr.getIterator().hasNext(),如果为 true 则使用 serverListMgr.getIterator().next() 更新 currentServerAddr,为 false 则递减 maxRetry,然后执行 serverListMgr.refreshCurrentServerAddr()

小结

ServerHttpAgent 实现了 HttpAgent 接口,其 httpGet、httpPost、httpDelete 方法的结构大体相同,都是以 do while 做循环,循环条件为距离开始执行时间不超过 readTimeoutMs

doc

  • ServerHttpAgent
退出移动版