HttpsUrlСоединение и поддержка - PullRequest
25 голосов
/ 30 марта 2012

Я использую com.sun.net.httpserver.HttpsServer в моем текущем проекте, который касается аутентификации клиента и т. Д. В настоящее время он только распечатывает адрес / порт клиента, чтобы я мог проверить, используется ли одно TCP-соединение для нескольких запросов (keep-alive) или если новое соединение устанавливается для каждого запроса (и, таким образом, каждый раз выполняется новое SSL-рукопожатие).Когда я использую FireFox для выполнения нескольких запросов к серверу, я вижу, что keep-alive работает.Таким образом, серверная часть отлично работает с GET и POST-запросами.

Если я использую HttpURLConnection, чтобы сделать запрос к Серверу (в этом случае с помощью нет SSL) keep-alive работаетКроме того, только одно соединение установлено для нескольких последовательно запускаемых запросов.

Но если я использую HttpsURLConnection (используя точно такой же код, но используя SSL), тогда keep-alive неработает больше.Таким образом, для каждого запроса устанавливается новое соединение, хотя я использую одно и то же SSLContextSSLSocketFactory):

// URL myUrl = ...
// SSLContext mySsl = ...
HttpsURLConnection conn = (HttpsURLConnection) myUrl.openConnection();
conn.setUseCaches(false);
conn.setSSLSocketFactory(mySsl.getSocketFactory());

conn.setRequestMethod("POST");
// send Data
// receive Data

Как заставить HttpsURLConnection использовать keep-alive, потому что много запросовприведет к множеству SSL-рукопожатий, что является реальной проблемой производительности?

Обновление (2012-04-02): Вместо того, чтобы каждый раз вызывать mySsl.getSocketFactory(), я пытался кэшировать SSLSocketFactory.Но ничего не изменилось.Проблема все еще существует.

Ответы [ 7 ]

17 голосов
/ 09 апреля 2015

Я столкнулся с точно такой же проблемой и, наконец, нашел решение после некоторой глубокой отладки.

Http (s) UrlConnection обрабатывает Keep-Alive по умолчанию, но сокеты должны находиться в очень специфическом состоянии вДля повторного использования.

Это:

  • Входные потоки должны быть полностью использованы.Вы должны вызывать read во входном потоке до тех пор, пока он не вернет -1, а также закрыть его.
  • В настройках базового сокета должны использоваться точно такие же объекты.
  • Вы должны вызвать disnect (да, этонелогично) на Http (s) URLConnection, когда сделано с ним.

В приведенном выше коде проблема заключается в:

conn.setSSLSocketFactory(mySsl.getSocketFactory());

Сохранение результата getSocketFactory ()статической переменной во время инициализации и последующей передачи ее в conn.setSSLSocketFactory, что позволит повторно использовать сокет.

5 голосов
/ 09 сентября 2012

Я не могу заставить его работать с HttpsUrlConnection. Но HTTP-клиент Apache отлично справляется с поддержкой SSL-соединений.

2 голосов
/ 03 апреля 2012

Установление SSL-соединения действительно дорого для сервисных вызовов или при получении большого количества ресурсов из браузера.

Java Http(s)UrlConnection обрабатывает HTTP (S) Keep-Alive по умолчанию .

Я не нашел исходный код SSLSocketFactory по умолчанию и, вероятно, там реализован механизм keep-alive.В качестве подтверждения отключите собственную реализацию SSLSocketFactory для теста с настраиваемым хранилищем доверия в javax.net.ssl.trustStore, чтобы ваш самозаверяющий сертификат был принят.

Согласно OpenJDK 7 ServerImpl реализация, которая использует ServerConfig HttpsServer, который вы использовали, выдает подтверждение активности с 5-минутным таймаутом по умолчанию.

Я предлагаю вам установить для свойства sun.net.httpserver.debug значение true server-сторона, чтобы получить детали.

Позаботьтесь, чтобы ваш код не добавил заголовок Connection: close, который отключает механизм поддержки активности.

0 голосов
/ 24 марта 2017

Я столкнулся с той же проблемой, и Билл Хили прав.Я протестировал мой пример кода ниже с несколькими библиотеками https.HttpsURLConnection и OKHTTP ведут себя одинаково.Залп немного отличается при возобновлении сеанса, но почти такое же поведение.Я надеюсь, что это поможет.

public class SampleActivity extends Activity implements OnClickListener {

    // Keep default context and factory
    private SSLContext mDefaultSslContext;
    private SSLSocketFactory mDefaultSslFactory;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        findViewById(R.id.button_id).setOnClickListener(this);

        try {
            // Initialize context and factory
            mDefaultSslContext = SSLContext.getInstance("TLS");
            mDefaultSslContext.init(null, null, null);
            mDefaultSslFactory = mDefaultSslContext.getSocketFactory();
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            Log.e(TAG, e.getMessage(), e);
        }

    }

    @Override
    public void onClick(View v){
        SSLContext sslcontext;
        SSLSocketFactory sslfactory;

        try {
            // If using this factory, enable Keep-Alive
            sslfactory = mDefaultSslFactory;

            // If using this factory, enable session resumption (abbreviated handshake)
            sslfactory = mDefaultSslContext.getSocketFactory();

            // If using this factory, enable full handshake each time
            sslcontext = SSLContext.getInstance("TLS");
            sslcontext.init(null, null, null);
            sslfactory = sslcontext.getSocketFactory();
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            Log.e(TAG, e.getMessage(), e);
        }

        URL url = new URL("https://example.com");
        HttpsURLConnection = conn = (HttpsURLConnection) url.openConnection();
        conn.setSSLSocketFactory(sslfactory);
        conn.connect();
    }
}

Обновление:

Совместное использование SSLSocketFactory позволяет поддерживать активность.Совместное использование SSLContext и получение facotry каждый запрос позволяют возобновить сеанс.Я не знаю, как работает стек TLS, но только подтвердил это поведение соединения с некоторыми мобильными устройствами.

Если вы хотите включить поддержку активности для нескольких классов, вы должны совместно использовать экземпляр SSLSocketFactory, используя шаблон синглтона.

Если вы хотите включить возобновление сеанса, убедитесь, что настройки тайм-аута сеанса достаточно велики на стороне сервера, такие как SSLSessionCacheTimeout (apache), ssl_session_timeout (nginx).

0 голосов
/ 23 сентября 2014

Мы можем настроить веб-сервер Apache, добавив следующие директивы, чтобы увидеть, имеет ли доступ access.log Apache к поддерживающему соединение для клиента http.

LogFormat "%k %v %h %l %u %t \"%r\" %>s %b" common
CustomLog "logs/access.log" common 

http://httpd.apache.org/docs/current/mod/mod_log_config.html

"% k" Количество запросов keepalive, обработанных для этого соединения. Интересно, если используется KeepAlive, например, «1» означает первый запрос keepalive после исходного, «2» - второй и т. Д.; в противном случае это всегда 0 (указывает на начальный запрос).

0 голосов
/ 09 апреля 2012

попробуйте добавить следующий код:

con.setRequestProperty("Connection", "Keep-Alive");
con.setRequestProperty("Keep-Alive", "header");
0 голосов
/ 02 апреля 2012

Насколько я понимаю, HTTP / 1.1 и HTTPS протокол, также задокументированный здесь , Keep-Alive не является end-to-end заголовок, но hop-to-hop заголовок.Поскольку SSL включает в себя несколько этапов установления связи между «различными прыжками» (например, CA и сервером) для каждого нового соединения, я думаю, что Keep-Alive может не применяться в контексте SSL.Таким образом, может быть причиной того, что заголовок Keep-Alive игнорируется при использовании соединений HTTPS.Исходя из этого этого вопроса , вам может потребоваться убедиться, что один экземпляр HTTP-соединения используется для гарантии Keep-Alive наблюдения.Кроме того, в вопросе кажется, что Apache HTTPClient был лучшим решением.

...