为什么从 Apache CloseableHttpClient (Java) 发送 2 个请求

问题描述 投票:0回答:0

我使用 httpclient-4.5.3(org.apache.httpcomponents).

创建了一个具有基本身份验证的 HTTP Post 请求
        CredentialsProvider provider = new BasicCredentialsProvider();
        provider.setCredentials(AuthScope.ANY,new UsernamePasswordCredentials("user","pass"));

        RequestConfig requestConfig = RequestConfig.custom().
                setConnectTimeout(2000).
                setSocketTimeout(2000).
                build();
       try (CloseableHttpClient httpClient = HttpClients.custom().
                setDefaultCredentialsProvider(provider).
                setDefaultRequestConfig(requestConfig).
                build()) {
            
            String reqString = mapper.writeValueAsString(obj); // here obj is a Java class of request payload
            StringEntity params = new StringEntity(reqString);
            HttpPost httpPost = new HttpPost(url); // server url where double requests are going
            httpPost.setHeader("Accept", "application/json");
            httpPost.setHeader("Content-type", "application/json");
            httpPost.setEntity(params);    

            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {

                final String jsonString = EntityUtils.toString(response.getEntity());

                if (200 == response.getStatusLine().getStatusCode()) {
                    mapper = new ObjectMapper();
                    
                } 
            }
        }

CloseableHttpResponse response = httpClient.execute(httpPost) 执行时,2 个请求发送到服务器,第一个请求在标头中没有基本授权,第二个请求在标头中带有基本授权。这是什么原因呢?

我深入研究了 httpclient-4.5.3 库,发现双重请求生成的实际点是 org.apache.http.impl.execchain.MainClientExec。在该类的 execute 方法中包含一个 for 循环,该循环实际上执行了 2 次。我在下面给出 for 循环...

    for (int execCount = 1;; execCount++) {

            if (execCount > 1 && !RequestEntityProxy.isRepeatable(request)) {
                throw new NonRepeatableRequestException("Cannot retry request " +
                        "with a non-repeatable request entity.");
            }

            if (execAware != null && execAware.isAborted()) {
                throw new RequestAbortedException("Request aborted");
            }

            if (!managedConn.isOpen()) {
                this.log.debug("Opening connection " + route);
                try {
                    establishRoute(proxyAuthState, managedConn, route, request, context);
                } catch (final TunnelRefusedException ex) {
                    if (this.log.isDebugEnabled()) {
                        this.log.debug(ex.getMessage());
                    }
                    response = ex.getResponse();
                    break;
                }
            }
            final int timeout = config.getSocketTimeout();
            if (timeout >= 0) {
                managedConn.setSocketTimeout(timeout);
            }

            if (execAware != null && execAware.isAborted()) {
                throw new RequestAbortedException("Request aborted");
            }

            if (this.log.isDebugEnabled()) {
                this.log.debug("Executing request " + request.getRequestLine());
            }

            if (!request.containsHeader(AUTH.WWW_AUTH_RESP)) {
                if (this.log.isDebugEnabled()) {
                    this.log.debug("Target auth state: " + targetAuthState.getState());
                }
                this.authenticator.generateAuthResponse(request, targetAuthState, context);
            }
            if (!request.containsHeader(AUTH.PROXY_AUTH_RESP) && !route.isTunnelled()) {
                if (this.log.isDebugEnabled()) {
                    this.log.debug("Proxy auth state: " + proxyAuthState.getState());
                }
                this.authenticator.generateAuthResponse(request, proxyAuthState, context);
            }

            response = requestExecutor.execute(request, managedConn, context);

            // The connection is in or can be brought to a re-usable state.
            if (reuseStrategy.keepAlive(response, context)) {
                // Set the idle duration of this connection
                final long duration = keepAliveStrategy.getKeepAliveDuration(response, context);
                if (this.log.isDebugEnabled()) {
                    final String s;
                    if (duration > 0) {
                        s = "for " + duration + " " + TimeUnit.MILLISECONDS;
                    } else {
                        s = "indefinitely";
                    }
                    this.log.debug("Connection can be kept alive " + s);
                }
                connHolder.setValidFor(duration, TimeUnit.MILLISECONDS);
                connHolder.markReusable();
            } else {
                connHolder.markNonReusable();
            }

            if (needAuthentication(
                    targetAuthState, proxyAuthState, route, response, context)) {
                // Make sure the response body is fully consumed, if present
                final HttpEntity entity = response.getEntity();
                if (connHolder.isReusable()) {
                    EntityUtils.consume(entity);
                } else {
                    managedConn.close();
                    if (proxyAuthState.getState() == AuthProtocolState.SUCCESS
                            && proxyAuthState.getAuthScheme() != null
                            && proxyAuthState.getAuthScheme().isConnectionBased()) {
                        this.log.debug("Resetting proxy auth state");
                        proxyAuthState.reset();
                    }
                    if (targetAuthState.getState() == AuthProtocolState.SUCCESS
                            && targetAuthState.getAuthScheme() != null
                            && targetAuthState.getAuthScheme().isConnectionBased()) {
                        this.log.debug("Resetting target auth state");
                        targetAuthState.reset();
                    }
                }
                // discard previous auth headers
                final HttpRequest original = request.getOriginal();
                if (!original.containsHeader(AUTH.WWW_AUTH_RESP)) {
                    request.removeHeaders(AUTH.WWW_AUTH_RESP);
                }
                if (!original.containsHeader(AUTH.PROXY_AUTH_RESP)) {
                    request.removeHeaders(AUTH.PROXY_AUTH_RESP);
                }
            } else {
                break;
            }
        }

任何人都可以告诉我为什么第一个请求在标头中不包含任何基本授权,但第二个请求包含该内容?

java apache xmlhttprequest basic-authentication apache-httpclient-4.x
© www.soinside.com 2019 - 2024. All rights reserved.