关于java:javanethttpHttpClient

41次阅读

共计 3360 个字符,预计需要花费 9 分钟才能阅读完成。

一、在应用 java 自带的 HttpClient 时,发现一个景象,即有些以前罕用 http 的 header,是不可能 set 到申请里进行传递的,在 jdk.internal.net.http.common.Utils 类中,能够看到

    private static Set<String> getDisallowedHeaders() {Set<String> headers = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
        headers.addAll(Set.of("connection", "content-length", "expect", "host", "upgrade"));

        String v = getNetProperty("jdk.httpclient.allowRestrictedHeaders");
        if (v != null) {
            // any headers found are removed from set.
            String[] tokens = v.trim().split(",");
            for (String token : tokens) {headers.remove(token);
            }
            return Collections.unmodifiableSet(headers);
        } else {return Collections.unmodifiableSet(headers);
        }
    }

connection, content-length, expect, host, upgrade 这几个,属于禁止设置的。因为在 jdk.internal.net.http.HttpRequestBuilderImpl 中,会进行严格的校验

    private void checkNameAndValue(String name, String value) {requireNonNull(name, "name");
        requireNonNull(value, "value");
        if (!isValidName(name)) {throw newIAE("invalid header name: \"%s\"", name);
        }
        if (!Utils.ALLOWED_HEADERS.test(name, null)) {throw newIAE("restricted header name: \"%s\"", name);
        }
        if (!isValidValue(value)) {throw newIAE("invalid header value: \"%s\"", value);
        }
    }

二、它本人管制连贯的复用,所以设置不了 connection 这个 header. 从 jdk.internal.net.http.ConnectionPool 中能够看出一些参数

static final long KEEP_ALIVE = Utils.getIntegerNetProperty("jdk.httpclient.keepalive.timeout", 1200); // seconds
static final long MAX_POOL_SIZE = Utils.getIntegerNetProperty("jdk.httpclient.connectionPoolSize", 0); // unbounded

从 jdk.internal.net.http.HttpConnection 中能够看到连贯如何放入池中

/**
     * Forces a call to the native implementation of the
     * connection's channel to verify that this channel is still
     * open.
     * <p>
     * This method should only be called just after an HTTP/1.1
     * connection is retrieved from the HTTP/1.1 connection pool.
     * It is used to trigger an early detection of the channel state,
     * before handling the connection over to the HTTP stack.
     * It helps minimizing race conditions where the selector manager
     * thread hasn't woken up - or hasn't raised the event, before
     * the connection was retrieved from the pool. It helps reduce
     * the occurrence of "HTTP/1.1 parser received no bytes"
     * exception, when the server closes the connection while
     * it's being taken out of the pool.
     * <p>
     * This method attempts to read one byte from the underlying
     * channel. Because the connection was in the pool - there
     * should be nothing to read.
     * <p>
     * If {@code read} manages to read a byte off the connection, this is a
     * protocol error: the method closes the connection and returns false.
     * If {@code read} returns EOF, the method closes the connection and
     * returns false.
     * If {@code read} throws an exception, the method returns false.
     * Otherwise, {@code read} returns 0, the channel appears to be
     * still open, and the method returns true.
     * @return true if the channel appears to be still open.
     */
    final boolean checkOpen() {if (isOpen()) {
            try {
                // channel is non blocking
                int read = channel().read(ByteBuffer.allocate(1));
                if (read == 0) return true;
                close();} catch (IOException x) {
                debug.log("Pooled connection is no longer operational: %s",
                        x.toString());
                return false;
            }
        }
        return false;
    }
    void closeOrReturnToCache(HttpHeaders hdrs) {if (hdrs == null) {
            // the connection was closed by server, eof
            Log.logTrace("Cannot return connection to pool: closing {0}", this);
            close();
            return;
        }
        HttpClientImpl client = client();
        if (client == null) {Log.logTrace("Client released: closing {0}", this);
            close();
            return;
        }
        ConnectionPool pool = client.connectionPool();
        boolean keepAlive = hdrs.firstValue("Connection")
                .map((s) -> !s.equalsIgnoreCase("close"))
                .orElse(true);

        if (keepAlive && checkOpen()) {Log.logTrace("Returning connection to the pool: {0}", this);
            pool.returnToPool(this);
        } else {Log.logTrace("Closing connection (keepAlive={0}, isOpen={1}): {2}",
                    keepAlive, isOpen(), this);
            close();}
    }

正文完
 0