简体   繁体   中英

java https client is slow

I'm trying to access web API via java.

The API is on https server.

Unfortunately it works very slow.

When I access the API via my web browser, it gives the response in 1 second.

When I access the API via java, it gives the response in 3 seconds.

What am I doing wrong? How can I get the response faster?

I noticed that the slow part is this line: HttpResponse response1 = httpclient.execute(httpGet);

Here's my code:

static DefaultHttpClient httpclient ;

static {
    UsernamePasswordCredentials creds = new UsernamePasswordCredentials("LOGIN", "PASSWORD");
     httpclient = new DefaultHttpClient();

     HttpHost targetHost = new HttpHost("SERVER.org", 443, "https");

    httpclient.getCredentialsProvider().setCredentials(
            new AuthScope(targetHost.getHostName(), targetHost.getPort()),
           creds);

    // Create AuthCache instance
    AuthCache authCache = new BasicAuthCache();
    // Generate BASIC scheme object and add it to the local
    // auth cache
    BasicScheme basicAuth = new BasicScheme();
    authCache.put(targetHost, basicAuth);

    // Add AuthCache to the execution context
    BasicHttpContext localcontext = new BasicHttpContext();
    localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);


  readXml("https://SERVER.org/PATH");
}



public static String readXml(String urlToRead){


    try {



        HttpGet httpGet = new HttpGet(urlToRead);

            HttpResponse response1 = httpclient.execute(httpGet);



        try {
            System.out.println(response1.getStatusLine());
            HttpEntity entity1 = response1.getEntity();



            BufferedReader in;
            String inputLine;
            String result="";
            try {

                in = new BufferedReader(new InputStreamReader(entity1.getContent(),"UTF-8"));
                while ((inputLine = in.readLine()) != null) {
                  result+=inputLine+"\n";
                }
                in.close();

            } catch (IOException e) {
                e.printStackTrace();
            }
            return result;


        } finally {
            httpGet.releaseConnection();
        }
    } catch (ClientProtocolException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

return null; }

I think it is slow in HTTPS handshake. There is no reason for new DefaultHttpClient in each request. You should use PoolingClientConnectionManager to handle multi-http-client.

public Client(int maxConnectPerHost, int maxConnection, int connectTimeOut, int socketTimeOut,
        String cookiePolicy, boolean isAutoRetry, boolean redirect) {
    SSLContext sslcontext = null;
    try {
        sslcontext = SSLContext.getInstance("SSL");
        sslcontext.init(null, new TrustManager[] {
            new TrustAnyTrustManager()
        }, new java.security.SecureRandom());
    } catch (Exception e) {
        // throw something
    }
    // if a ssl certification is not correct, it will not throw any exceptions.
    Scheme https = new Scheme("https", 443, new SSLSocketFactory(sslcontext,
            SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER));
    Scheme http = new Scheme("http", 80, PlainSocketFactory.getSocketFactory());
    SchemeRegistry sr = new SchemeRegistry();
    sr.register(https);
    sr.register(http);

    connectionManager = new PoolingClientConnectionManager(sr, socketTimeOut, TimeUnit.SECONDS);
    connectionManager.setDefaultMaxPerRoute(maxConnectPerHost);
    connectionManager.setMaxTotal(maxConnection);
    HttpParams params = new BasicHttpParams();
    params.setLongParameter(ClientPNames.CONN_MANAGER_TIMEOUT, connectTimeOut);
    params.setParameter(ClientPNames.COOKIE_POLICY, cookiePolicy);
    params.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, redirect);
    params.setBooleanParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, false);

    if (isAutoRetry) {
        client = new AutoRetryHttpClient(new DefaultHttpClient(connectionManager, params));
    } else {
        client = new DefaultHttpClient(connectionManager, params);
    }
}

and then use the client to send request. The client should be a singleton. Here is the doGet method. And the connection should not be released.

public HttpResponse doGet(String url, List<Header> headers)
            throws Exception {

    HttpGet get = new HttpGet(url);
    if (headers != null) {
        Header[] array = new Header[headers.size()];
        headers.toArray(array);
        get.setHeaders(array);
    }

    try {
        HttpResponse resp = client.execute(get);
        return resp;
    } catch (Exception e) {
        // throw something
    } 
}

Here is the request:

Client c = new Client(1024, 1024 * 1024, 10000, 10000, CookiePolicy.IGNORE_COOKIES, true, true);
HttpResponse r = null;
try {
    r = c.doGet("your url", null);
} finally{
    if (r != null) {
        EntityUtils.consumeQuietly(r.getEntity());
    }
}


// send request again. There is no https handshake in this time.
   try {
        r = c.doGet("your url", null);
    } finally{
        if (r != null) {
            EntityUtils.consumeQuietly(r.getEntity());
        }
    }

The handshake will be slow down your application. So you should not close/release connection in each request.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM