Saturday, June 4, 2016

Http Misc



https://blogs.oracle.com/japod/entry/how_to_use_jersey_client

http://www.baeldung.com/httpclient-connection-management
The PoolingHttpClientConnectionManager will create and manage a pool of connections for each route or target host we use. The default size of the pool of concurrent connections that can be open by the manager is 2 for each route or target host, and 20 for total open connections. 

Notice the EntityUtils.consume(response.getEntity) call – necessary to consume the entire content of the response (entity) so that the manager can release the connection back to the pool.
org.apache.http.util.EntityUtils.consume(HttpEntity)
    public static void consume(final HttpEntity entity) throws IOException {
        if (entity == null) {
            return;
        }
        if (entity.isStreaming()) {
            final InputStream instream = entity.getContent();
            if (instream != null) {
                instream.close();
            }
        }

    }
If the Keep-Alive header is not present in the response,HttpClient assumes the connection can be kept alive indefinitely.” (See the HttpClient Reference).
ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() {
    @Override
    public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
        HeaderElementIterator it = new BasicHeaderElementIterator
            (response.headerIterator(HTTP.CONN_KEEP_ALIVE));
        while (it.hasNext()) {
            HeaderElement he = it.nextElement();
            String param = he.getName();
            String value = he.getValue();
            if (value != null && param.equalsIgnoreCase
               ("timeout")) {
                return Long.parseLong(value) * 1000;
            }
        }
        return 5 * 1000;
    }
};
This strategy will first try to apply the host’s Keep-Alive policy stated in the header. If that information is not present in the response header it will keep alive connections for 5 seconds.
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
CloseableHttpClient client = HttpClients.custom().setKeepAliveStrategy(myStrategy).
    setConnectionManager(connManager).build();

The HTTP/1.1 Spec states that connections can be re-used if they have not been closed – this is known as connection persistence.
Once a connection is released by the manager it stays open for re-use. When using aBasicHttpClientConnectionManager, which can only mange a single connection, the connection must be released before it is leased back again:
The only timeout that can be set at the time when connection manager is configured is the socket timeout:
Connection eviction is used to detect idle and expired connections and close them; there are two options to do this.
  1. Relying on the HttpClient to check if the connection is stale before executing a request. This is an expensive option that is not always reliable.
  2. Create a monitor thread to close idle and/or closed connections.
Setting the HttpClient to Check for Stale Connections
1
2
3
4
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
CloseableHttpClient client = HttpClients.custom().setDefaultRequestConfig(
    RequestConfig.custom().setStaleConnectionCheckEnabled(true).build()).
    setConnectionManager(connManager).build();
Using a Stale Connection Monitor Thread
public class IdleConnectionMonitorThread extends Thread {
    private final HttpClientConnectionManager connMgr;
    private volatile boolean shutdown;
 
    public IdleConnectionMonitorThread
      (PoolingHttpClientConnectionManager connMgr) {
        super();
        this.connMgr = connMgr;
    }
    @Override
    public void run() {
        try {
            while (!shutdown) {
                synchronized (this) {
                    wait(1000);
                    connMgr.closeExpiredConnections();
                    connMgr.closeIdleConnections(30, TimeUnit.SECONDS);
                }
            }
        } catch (InterruptedException ex) {
            shutdown();
        }
    }
    public void shutdown() {
        shutdown = true;
        synchronized (this) {
            notifyAll();
        }
    }
}
A connection can be closed gracefully (an attempt to flush the output buffer prior to closing is made), or forcefully, by calling the shutdown method (the output buffer is not flushed). To properly close connections we need to do all of the following:
  • consume and close the response (if closeable)
  • close the client
  • close and shut down the connection manager
connManager = new PoolingHttpClientConnectionManager();
CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build();
HttpGet get = new HttpGet("http://google.com");
CloseableHttpResponse response = client.execute(get);
 
EntityUtils.consume(response.getEntity());
response.close();
client.close();
connManager.close();
If the manager is shut down without connections being closed already – all connections will be closed and all resources released. It’s important to keep in mind that this will not flush any data that may have been ongoing in the existing connections.
http://www.baeldung.com/httpclient-timeout
  • the Connection Timeout (http.connection.timeout) – the time to establish the connection with the remote host
  • the Socket Timeout (http.socket.timeout) – the time waiting for data – after the connection was established; maximum time of inactivity between two data packets
  • the Connection Manager Timeout (http.connection-manager.timeout) – the time to wait for a connection from the connection manager/pool
The first two parameters – the connection and socket timeouts – are the most important, but setting a timeout for obtaining a connection is definitely important in high load scenarios, which is why the third parameter shouldn’t be ignored.
Note that the connection timeout will result in aorg.apache.http.conn.ConnectTimeoutException being thrown, while socket timeout will result in java.net.SocketTimeoutException.
we need to set a hard timeout for the entire request.
 
int hardTimeout = 5; // seconds
TimerTask task = new TimerTask() {
    @Override
    public void run() {
        if (getMethod != null) {
            getMethod.abort();
        }
    }
};
new Timer(true).schedule(task, hardTimeout * 1000);
 
HttpResponse response = httpClient.execute(getMethod);

Timeout and DNS Round Robin – something to be aware of

It is quite common that some larger domains will be using a DNS round robin configuration – essentially having the same domain mapped to multiple IP addresses. This introduces a new challenge for timeout against such a domain, simply because of the way HttpClient will try to connect to that domain that times out:

  • HttpClient gets the list of IP routes to that domain
  • it tries the first one – that times out (with the timeouts we configure)
  • it tries the second one – that also times out
  • and so on …
So, as you can see – the overall operation will not time out when we expect it to. Instead – it will time out when all the possible routes have timed out, and what it more – this will happen completely transparently for the client (unless you have your log configured at the DEBUG level). Here is a simple example you can run and replicate this issue:
1
2
3
4
5
6
7
8
9
int timeout = 3;
RequestConfig config = RequestConfig.custom().
  setConnectTimeout(timeout * 1000).
  setConnectionRequestTimeout(timeout * 1000).
  setSocketTimeout(timeout * 1000).build();
CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
 
HttpGet request = new HttpGet("http://www.google.com:81");
response = client.execute(request);
You will notice the retrying logic with a DEBUG log level:
1
2
3
4
5
6
7
8
9
10
11
12
DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.212:81
DEBUG o.a.h.i.c.HttpClientConnectionOperator -
 Connect to www.google.com/173.194.34.212:81 timed out. Connection will be retried using another IP address
 
DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.208:81
DEBUG o.a.h.i.c.HttpClientConnectionOperator -
 Connect to www.google.com/173.194.34.208:81 timed out. Connection will be retried using another IP address
 
DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.209:81
DEBUG o.a.h.i.c.HttpClientConnectionOperator -
 Connect to www.google.com/173.194.34.209:81 timed out. Connection will be retried using another IP address
...
http://www.baeldung.com/unshorten-url-httpclient
an http client that doesn’t automatically follow redirects:

http://stackoverflow.com/questions/5273579/how-to-clone-a-detached-httpservletrequest-and-httpservletresponse-provided-by-t
Cloning HTTP request and response is possible via HttpServletResponseWrapper classhttp://docs.oracle.com/javaee/1.3/api/javax/servlet/http/HttpServletResponseWrapper.html. You can find an example of usage on Sun documentationhttps://web.archive.org/web/20120626033905/http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/Servlets8.html.
Notice this was a workaround from (at that time) Sun to address this problem as it was never planned that you could modify request and response information before committed.
Chunked transfer encoding is a data transfer mechanism in version 1.1 of the Hypertext Transfer Protocol (HTTP) in which data is sent in a series of "chunks". It uses the Transfer-EncodingHTTP header in place of the Content-Length header, which the earlier version of the protocol would otherwise require.[1] Because the Content-Length header is not used, the sender does not need to know the length of the content before it starts transmitting a response to the receiver. Senders can begin transmitting dynamically-generated content before knowing the total size of that content.
The size of each chunk is sent right before the chunk itself so that the receiver can tell when it has finished receiving data for that chunk. The data transfer is terminated by a final chunk of length zero.



Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts