成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

聊聊jdk http的HeaderFilter

233jl / 2913人閱讀

摘要:序本文主要研究一下的。提供了及方法,前者添加,后者使用反射實例化。其中是按順序執(zhí)行,而則取的是,逆序執(zhí)行

本文主要研究一下jdk http的HeaderFilter。

FilterFactory

java.net.http/jdk/internal/net/http/FilterFactory.java

class FilterFactory {

    // Strictly-ordered list of filters.
    final LinkedList> filterClasses = new LinkedList<>();

    public void addFilter(Class type) {
        filterClasses.add(type);
    }

    LinkedList getFilterChain() {
        LinkedList l = new LinkedList<>();
        for (Class clazz : filterClasses) {
            try {
                // Requires a public no arg constructor.
                HeaderFilter headerFilter = clazz.getConstructor().newInstance();
                l.add(headerFilter);
            } catch (ReflectiveOperationException e) {
                throw new InternalError(e);
            }
        }
        return l;
    }
}

提供了addFilter及getFilterChain方法,前者添加filter class,后者使用反射實例化filter。

HttpClientImpl

java.net.http/jdk/internal/net/http/HttpClientImpl.java

    private HttpClientImpl(HttpClientBuilderImpl builder,
                           SingleFacadeFactory facadeFactory) {
        id = CLIENT_IDS.incrementAndGet();
        dbgTag = "HttpClientImpl(" + id +")";
        if (builder.sslContext == null) {
            try {
                sslContext = SSLContext.getDefault();
            } catch (NoSuchAlgorithmException ex) {
                throw new InternalError(ex);
            }
        } else {
            sslContext = builder.sslContext;
        }
        Executor ex = builder.executor;
        if (ex == null) {
            ex = Executors.newCachedThreadPool(new DefaultThreadFactory(id));
            isDefaultExecutor = true;
        } else {
            isDefaultExecutor = false;
        }
        delegatingExecutor = new DelegatingExecutor(this::isSelectorThread, ex);
        facadeRef = new WeakReference<>(facadeFactory.createFacade(this));
        client2 = new Http2ClientImpl(this);
        cookieHandler = builder.cookieHandler;
        connectTimeout = builder.connectTimeout;
        followRedirects = builder.followRedirects == null ?
                Redirect.NEVER : builder.followRedirects;
        this.userProxySelector = Optional.ofNullable(builder.proxy);
        this.proxySelector = userProxySelector
                .orElseGet(HttpClientImpl::getDefaultProxySelector);
        if (debug.on())
            debug.log("proxySelector is %s (user-supplied=%s)",
                      this.proxySelector, userProxySelector.isPresent());
        authenticator = builder.authenticator;
        if (builder.version == null) {
            version = HttpClient.Version.HTTP_2;
        } else {
            version = builder.version;
        }
        if (builder.sslParams == null) {
            sslParams = getDefaultParams(sslContext);
        } else {
            sslParams = builder.sslParams;
        }
        connections = new ConnectionPool(id);
        connections.start();
        timeouts = new TreeSet<>();
        try {
            selmgr = new SelectorManager(this);
        } catch (IOException e) {
            // unlikely
            throw new InternalError(e);
        }
        selmgr.setDaemon(true);
        filters = new FilterFactory();
        initFilters();
        assert facadeRef.get() != null;
    }

    private void initFilters() {
        addFilter(AuthenticationFilter.class);
        addFilter(RedirectFilter.class);
        if (this.cookieHandler != null) {
            addFilter(CookieFilter.class);
        }
    }

    private void addFilter(Class f) {
        filters.addFilter(f);
    }

    final LinkedList filterChain() {
        return filters.getFilterChain();
    }

HttpClientImpl的構(gòu)造器創(chuàng)建了FilterFactory,并調(diào)用addFilter添加默認(rèn)的filter

filterChain方法則調(diào)用了FilterFactory的getFilterChain()方法,使用反射實例化這些filter

MultiExchange

java.net.http/jdk/internal/net/http/MultiExchange.java

    /**
     * MultiExchange with one final response.
     */
    MultiExchange(HttpRequest userRequest,
                  HttpRequestImpl requestImpl,
                  HttpClientImpl client,
                  HttpResponse.BodyHandler responseHandler,
                  PushPromiseHandler pushPromiseHandler,
                  AccessControlContext acc) {
        this.previous = null;
        this.userRequest = userRequest;
        this.request = requestImpl;
        this.currentreq = request;
        this.previousreq = null;
        this.client = client;
        this.filters = client.filterChain();
        this.acc = acc;
        this.executor = client.theExecutor();
        this.responseHandler = responseHandler;

        if (pushPromiseHandler != null) {
            Executor executor = acc == null
                    ? this.executor.delegate()
                    : new PrivilegedExecutor(this.executor.delegate(), acc);
            this.pushGroup = new PushGroup<>(pushPromiseHandler, request, executor);
        } else {
            pushGroup = null;
        }

        this.exchange = new Exchange<>(request, this);
    }

    private CompletableFuture responseAsyncImpl() {
        CompletableFuture cf;
        if (attempts.incrementAndGet() > max_attempts) {
            cf = failedFuture(new IOException("Too many retries", retryCause));
        } else {
            if (currentreq.timeout().isPresent()) {
                responseTimerEvent = ResponseTimerEvent.of(this);
                client.registerTimer(responseTimerEvent);
            }
            try {
                // 1. apply request filters
                // if currentreq == previousreq the filters have already
                // been applied once. Applying them a second time might
                // cause some headers values to be added twice: for
                // instance, the same cookie might be added again.
                if (currentreq != previousreq) {
                    requestFilters(currentreq);
                }
            } catch (IOException e) {
                return failedFuture(e);
            }
            Exchange exch = getExchange();
            // 2. get response
            cf = exch.responseAsync()
                     .thenCompose((Response response) -> {
                        HttpRequestImpl newrequest;
                        try {
                            // 3. apply response filters
                            newrequest = responseFilters(response);
                        } catch (IOException e) {
                            return failedFuture(e);
                        }
                        // 4. check filter result and repeat or continue
                        if (newrequest == null) {
                            if (attempts.get() > 1) {
                                Log.logError("Succeeded on attempt: " + attempts);
                            }
                            return completedFuture(response);
                        } else {
                            this.response =
                                new HttpResponseImpl<>(currentreq, response, this.response, null, exch);
                            Exchange oldExch = exch;
                            return exch.ignoreBody().handle((r,t) -> {
                                previousreq = currentreq;
                                currentreq = newrequest;
                                expiredOnce = false;
                                setExchange(new Exchange<>(currentreq, this, acc));
                                return responseAsyncImpl();
                            }).thenCompose(Function.identity());
                        } })
                     .handle((response, ex) -> {
                        // 5. handle errors and cancel any timer set
                        cancelTimer();
                        if (ex == null) {
                            assert response != null;
                            return completedFuture(response);
                        }
                        // all exceptions thrown are handled here
                        CompletableFuture errorCF = getExceptionalCF(ex);
                        if (errorCF == null) {
                            return responseAsyncImpl();
                        } else {
                            return errorCF;
                        } })
                     .thenCompose(Function.identity());
        }
        return cf;
    }

    private void requestFilters(HttpRequestImpl r) throws IOException {
        Log.logTrace("Applying request filters");
        for (HeaderFilter filter : filters) {
            Log.logTrace("Applying {0}", filter);
            filter.request(r, this);
        }
        Log.logTrace("All filters applied");
    }

    private HttpRequestImpl responseFilters(Response response) throws IOException
    {
        Log.logTrace("Applying response filters");
        Iterator reverseItr = filters.descendingIterator();
        while (reverseItr.hasNext()) {
            HeaderFilter filter = reverseItr.next();
            Log.logTrace("Applying {0}", filter);
            HttpRequestImpl newreq = filter.response(response);
            if (newreq != null) {
                Log.logTrace("New request: stopping filters");
                return newreq;
            }
        }
        Log.logTrace("All filters applied");
        return null;
    }

MultiExchange在構(gòu)造器里頭調(diào)用了client.filterChain(),完成filters的初始化

在responseAsyncImpl方法里頭,執(zhí)行請求之前調(diào)用requestFilters,得到response之后調(diào)用responseFilters

requestFilters是按順序執(zhí)行,而responseFilters則取的是descendingIterator,逆序執(zhí)行

HeaderFilter

java.net.http/jdk/internal/net/http/HeaderFilter.java

/**
 * A header filter that can examine or modify, typically system headers for
 * requests before they are sent, and responses before they are returned to the
 * user. Some ability to resend requests is provided.
 */
interface HeaderFilter {

    void request(HttpRequestImpl r, MultiExchange e) throws IOException;

    /**
     * Returns null if response ok to be given to user.  Non null is a request
     * that must be resent and its response given to user. If impl throws an
     * exception that is returned to user instead.
     */
    HttpRequestImpl response(Response r) throws IOException;
}

可以看到HeaderFilter接口定義了request以及response方法

對于response方法,如果對header處理沒問題就返回null,有異常拋異常,需要重新發(fā)送的則會返回HttpRequestImpl

HeaderFilter有三個實現(xiàn)類,分別是AuthenticationFilter、RedirectFilter、CookieFilter

AuthenticationFilter

java.net.http/jdk/internal/net/http/AuthenticationFilter.java

    @Override
    public void request(HttpRequestImpl r, MultiExchange e) throws IOException {
        // use preemptive authentication if an entry exists.
        Cache cache = getCache(e);
        this.exchange = e;

        // Proxy
        if (exchange.proxyauth == null) {
            URI proxyURI = getProxyURI(r);
            if (proxyURI != null) {
                CacheEntry ca = cache.get(proxyURI, true);
                if (ca != null) {
                    exchange.proxyauth = new AuthInfo(true, ca.scheme, null, ca);
                    addBasicCredentials(r, true, ca.value);
                }
            }
        }

        // Server
        if (exchange.serverauth == null) {
            CacheEntry ca = cache.get(r.uri(), false);
            if (ca != null) {
                exchange.serverauth = new AuthInfo(true, ca.scheme, null, ca);
                addBasicCredentials(r, false, ca.value);
            }
        }
    }

    // TODO: refactor into per auth scheme class
    private static void addBasicCredentials(HttpRequestImpl r,
                                            boolean proxy,
                                            PasswordAuthentication pw) {
        String hdrname = proxy ? "Proxy-Authorization" : "Authorization";
        StringBuilder sb = new StringBuilder(128);
        sb.append(pw.getUserName()).append(":").append(pw.getPassword());
        String s = encoder.encodeToString(sb.toString().getBytes(ISO_8859_1));
        String value = "Basic " + s;
        if (proxy) {
            if (r.isConnect()) {
                if (!Utils.PROXY_TUNNEL_FILTER.test(hdrname, value)) {
                    Log.logError("{0} disabled", hdrname);
                    return;
                }
            } else if (r.proxy() != null) {
                if (!Utils.PROXY_FILTER.test(hdrname, value)) {
                    Log.logError("{0} disabled", hdrname);
                    return;
                }
            }
        }
        r.setSystemHeader(hdrname, value);
    }

   @Override
    public HttpRequestImpl response(Response r) throws IOException {
        Cache cache = getCache(exchange);
        int status = r.statusCode();
        HttpHeaders hdrs = r.headers();
        HttpRequestImpl req = r.request();

        if (status != UNAUTHORIZED && status != PROXY_UNAUTHORIZED) {
            // check if any authentication succeeded for first time
            if (exchange.serverauth != null && !exchange.serverauth.fromcache) {
                AuthInfo au = exchange.serverauth;
                cache.store(au.scheme, req.uri(), false, au.credentials);
            }
            if (exchange.proxyauth != null && !exchange.proxyauth.fromcache) {
                AuthInfo au = exchange.proxyauth;
                URI proxyURI = getProxyURI(req);
                if (proxyURI != null) {
                    cache.store(au.scheme, proxyURI, true, au.credentials);
                }
            }
            return null;
        }
        //......
    }

可以用于添加basic authentication的header

RedirectFilter

java.net.http/jdk/internal/net/http/RedirectFilter.java

    @Override
    public synchronized void request(HttpRequestImpl r, MultiExchange e) throws IOException {
        this.request = r;
        this.client = e.client();
        this.policy = client.followRedirects();

        this.method = r.method();
        this.uri = r.uri();
        this.exchange = e;
    }

    @Override
    public synchronized HttpRequestImpl response(Response r) throws IOException {
        return handleResponse(r);
    }

    /**
     * Checks to see if a new request is needed and returns it.
     * Null means response is ok to return to user.
     */
    private HttpRequestImpl handleResponse(Response r) {
        int rcode = r.statusCode();
        if (rcode == 200 || policy == HttpClient.Redirect.NEVER) {
            return null;
        }

        if (rcode == HTTP_NOT_MODIFIED)
            return null;

        if (rcode >= 300 && rcode <= 399) {
            URI redir = getRedirectedURI(r.headers());
            String newMethod = redirectedMethod(rcode, method);
            Log.logTrace("response code: {0}, redirected URI: {1}", rcode, redir);
            if (canRedirect(redir) && ++exchange.numberOfRedirects < max_redirects) {
                Log.logTrace("redirect to: {0} with method: {1}", redir, newMethod);
                return HttpRequestImpl.newInstanceForRedirection(redir, newMethod, request);
            } else {
                Log.logTrace("not redirecting");
                return null;
            }
        }
        return null;
    }

主要用于處理3xx跳轉(zhuǎn),這個時候滿足條件的話會返回新的HttpRequestImpl實例

CookieFilter

java.net.http/jdk/internal/net/http/CookieFilter.java

    @Override
    public void request(HttpRequestImpl r, MultiExchange e) throws IOException {
        HttpClientImpl client = e.client();
        Optional cookieHandlerOpt = client.cookieHandler();
        if (cookieHandlerOpt.isPresent()) {
            CookieHandler cookieHandler = cookieHandlerOpt.get();
            Map> userheaders = r.getUserHeaders().map();
            Map> cookies = cookieHandler.get(r.uri(), userheaders);

            // add the returned cookies
            HttpHeadersBuilder systemHeadersBuilder = r.getSystemHeadersBuilder();
            if (cookies.isEmpty()) {
                Log.logTrace("Request: no cookie to add for {0}", r.uri());
            } else {
                Log.logTrace("Request: adding cookies for {0}", r.uri());
            }
            for (Map.Entry> entry : cookies.entrySet()) {
                final String hdrname = entry.getKey();
                if (!hdrname.equalsIgnoreCase("Cookie")
                        && !hdrname.equalsIgnoreCase("Cookie2"))
                    continue;
                List values = entry.getValue();
                if (values == null || values.isEmpty()) continue;
                for (String val : values) {
                    if (Utils.isValidValue(val)) {
                        systemHeadersBuilder.addHeader(hdrname, val);
                    }
                }
            }
        } else {
            Log.logTrace("Request: No cookie manager found for {0}", r.uri());
        }
    }

    @Override
    public HttpRequestImpl response(Response r) throws IOException {
        HttpHeaders hdrs = r.headers();
        HttpRequestImpl request = r.request();
        Exchange e = r.exchange;
        Log.logTrace("Response: processing cookies for {0}", request.uri());
        Optional cookieHandlerOpt = e.client().cookieHandler();
        if (cookieHandlerOpt.isPresent()) {
            CookieHandler cookieHandler = cookieHandlerOpt.get();
            Log.logTrace("Response: parsing cookies from {0}", hdrs.map());
            cookieHandler.put(request.uri(), hdrs.map());
        } else {
            Log.logTrace("Response: No cookie manager found for {0}",
                         request.uri());
        }
        return null;
    }

用于請求以及響應(yīng)的cookie相關(guān)的處理

小結(jié)

FilterFactory使用了簡單的責(zé)任鏈模式,getFilterChain方法使用反射實例化各種filter

HeaderFilter定義了request及response兩個方法,分別作用于請求前及獲得響應(yīng)之后

HeaderFilter有三個實現(xiàn)類,分別是AuthenticationFilter、RedirectFilter、CookieFilter

MultiExchange在responseAsyncImpl方法里頭,執(zhí)行請求之前調(diào)用requestFilters,得到response之后調(diào)用responseFilters。其中requestFilters是按順序執(zhí)行,而responseFilters則取的是descendingIterator,逆序執(zhí)行

doc

java.net.http javadoc

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/77323.html

相關(guān)文章

  • 聊聊jdk httpclientconnect timeout異常

    摘要:序本文主要研究一下的異常實例代碼異常日志如下最后調(diào)用這里調(diào)用獲取連接如果沒有連接會新創(chuàng)建一個,走的是這里先是調(diào)用了獲取連接,然后調(diào)用進(jìn)行連接這里委托給這里如果有設(shè)置的話,則會創(chuàng)建一個調(diào)用進(jìn)行連接,如果連接未 序 本文主要研究一下httpclient的connect timeout異常 實例代碼 @Test public void testConnectTimeout()...

    張利勇 評論0 收藏0
  • [case39]聊聊jdk httpclientexecutor

    摘要:序本文主要研究一下的這里如果的為,則會創(chuàng)建這里如果是的話,參數(shù)傳遞的是如果是同步的方法,則傳的值是這里創(chuàng)建了一個,然后調(diào)用,這里使用了可以看到這里使用的是的方法注意這個方法是才有的,也是在這里使用的由于默認(rèn)是使用創(chuàng)建的, 序 本文主要研究一下jdk httpclient的executor HttpClientImpl java.net.http/jdk/internal/net/htt...

    dabai 評論0 收藏0
  • 聊聊jdk httpclientretry參數(shù)

    摘要:序本文主要研究一下的參數(shù)這里有一個類型的變量,用來記錄請求次數(shù)另外還有一個,讀取的是值,讀取不到默認(rèn)取,為進(jìn)入該方法的時候,調(diào)用,遞增請求次數(shù),然后判斷有無超出限制,有則返回帶有異常的,即通過返回如果沒有超出限制,但是執(zhí)行請求失敗,則 序 本文主要研究一下jdk httpclient的retry參數(shù) DEFAULT_MAX_ATTEMPTS java.net.http/jdk/inte...

    ityouknow 評論0 收藏0
  • 聊聊jdk httpclientConnectionPool

    摘要:調(diào)用計算的時間,這個方法會清理移除并過期的連接除了清理過期的連接外,還通過間接觸發(fā),去清理關(guān)閉或異常的連接 序 本文主要研究一下jdk httpclient的ConnectionPool HttpConnection HttpConnection.getConnection java.net.http/jdk/internal/net/http/HttpConnection.java ...

    Worktile 評論0 收藏0
  • 聊聊 Java8 以后各個版本新特性

    摘要:于是抽時間看了看以后各個版本的特性,做了一個總結(jié)。年和公開版本發(fā)布,取名為。此后對應(yīng)版本就是,。發(fā)布,是一個重大版本更新。在此之后,就是每六個月發(fā)布一次新版本。以上和參考資料聊了一些關(guān)于的歷史,下面我們看看各個版本有那些新特性。 【這是 ZY 第 11 篇原創(chuàng)技術(shù)文章】 某天在網(wǎng)上閑逛,突然看到有篇介紹 Java 11 新特性的文章,頓時心里一驚,畢竟我對于 Java 的版本認(rèn)識...

    K_B_Z 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<