java https keep-alive

java - HttpsUrlConnection y keep-alive



(7)

El establecimiento de la conexión SSL es realmente costoso para llamadas de servicio o para obtener muchos recursos de un navegador.

Java Http(s)UrlConnection maneja HTTP (S) Keep-Alive de forma predeterminada .

No he encontrado el código fuente del SSLSocketFactory predeterminado y probablemente el mecanismo de mantener vivo está implementado allí. Como confirmación, deshabilite su propia implementación SSLSocketFactory para una prueba, con un almacén de confianza personalizado en javax.net.ssl.trustStore para que se javax.net.ssl.trustStore su certificado autofirmado.

Según la implementación de OpenJDK 7 ServerImpl que utiliza ServerConfig, el HttpsServer que utilizó emite un keep-alive con un tiempo de espera de 5 minutos por defecto.

Propongo que establezca la propiedad sun.net.httpserver.debug en el lado del servidor true para obtener detalles.

Tenga cuidado de que su código no agregue el encabezado Connection: close que desactiva el mecanismo keep-alive.

Estoy utilizando com.sun.net.httpserver.HttpsServer en mi proyecto actual, que trata de la autenticación del cliente, etc. Actualmente, solo imprime la dirección / puerto del cliente, de modo que pueda verificar si una conexión TCP se usa para múltiples solicitudes ( keep-alive ) o si se establece una nueva conexión para cada solicitud (y, por lo tanto, se realiza un nuevo protocolo SSL-handshake cada vez). Cuando uso FireFox para hacer múltiples solicitudes contra el servidor, puedo ver que keep-alive está funcionando. Entonces, la parte del servidor funciona bien con las solicitudes GET y POST.

Si utilizo HttpURLConnection para realizar una solicitud contra el Servidor (en este caso, sin usar SSL) también funciona keep-alive : solo se establece una conexión para múltiples solicitudes iniciadas secuencialmente.

Pero si uso HttpsURLConnection (usando exactamente el mismo código, pero usando SSL) entonces keep-alive ya no funciona. Entonces, para cada solicitud se establece una nueva conexión, aunque estoy usando el mismo SSLContext (y SSLSocketFactory ):

// URL myUrl = ... // SSLContext mySsl = ... HttpsURLConnection conn = (HttpsURLConnection) myUrl.openConnection(); conn.setUseCaches(false); conn.setSSLSocketFactory(mySsl.getSocketFactory()); conn.setRequestMethod("POST"); // send Data // receive Data

¿Cómo HttpsURLConnection a HttpsURLConnection a utilizar keep-alive porque muchas solicitudes darán lugar a muchos apretones de manos SSL, que es un problema real de rendimiento?

Actualización (2012-04-02): en lugar de llamar a mySsl.getSocketFactory() cada vez, traté de almacenar en caché el SSLSocketFactory . Pero nada cambió. El problema todavía existe


Enfrenté el mismo problema, y ​​Bill Healey tiene razón. Probé mi código de ejemplo a continuación con algunas bibliotecas https. HttpsURLConnection y OKHTTP son exactamente el mismo comportamiento. Volley es un poco diferente cuando se reanuda la sesión, pero casi el mismo comportamiento. Espero que esto sea de alguna ayuda.

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(); } }

Actualizar:

Compartir SSLSocketFactory habilita keep-alive. Al compartir SSLContext y obtener facotry cada solicitud, se habilita la reanudación de la sesión. No sé cómo funciona la pila TLS, pero simplemente confirmó estos comportamientos de conexión con algunos dispositivos móviles.

Si desea habilitar keep-alive entre varias clases, debe compartir la instancia de SSLSocketFactory usando un patrón singleton.

Si desea habilitar la reanudación de la sesión, asegúrese de que la configuración de tiempo de espera de la sesión sea lo suficientemente larga en el lado del servidor, como SSLSessionCacheTimeout (apache), ssl_session_timeout (nginx).


Me encontré con este mismo problema exacto y, finalmente, tengo una solución después de una depuración en profundidad.

Http (s) UrlConnection maneja Keep-Alive por defecto, pero los sockets deben estar en una condición muy específica para ser reutilizados.

Estos son:

  • Los flujos de entrada deben consumirse por completo. Debe llamar a read on the stream de entrada hasta que devuelva -1 y también cerrarlo.
  • Las configuraciones en el socket subyacente deben usar exactamente los mismos objetos.
  • Debería llamar a desconexión (sí, esto es contrario a la intuición) en Http (s) URLConnection cuando haya terminado con él.

En el código anterior, el problema es:

conn.setSSLSocketFactory(mySsl.getSocketFactory());

Guardar el resultado de getSocketFactory () en una variable estática durante la inicialización y luego pasarlo a conn.setSSLSocketFactory debería permitir que el socket se reutilice.


No pude hacer que funcione con HttpsUrlConnection . Pero el cliente HTTP de Apache maneja muy bien las conexiones keep-alive con SSL.


Podemos configurar un servidor web Apache, agregar las siguientes directivas para ver si el access.log de Apache tiene una conexión keep-alive para el cliente 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" Número de solicitudes de keepalive manejadas en esta conexión. Es interesante si se usa KeepAlive, de modo que, por ejemplo, un ''1'' significa la primera solicitud de keepalive después de la inicial, ''2'' la segunda, etc ...; de lo contrario, esto siempre es 0 (indicando la solicitud inicial).


Por lo que puedo entender el protocolo HTTP / 1.1 y HTTPS , también documentado aquí , Keep-Alive no es un encabezado de extremo a extremo sino un encabezado de salto a salto . Como SSL implica varios pasos de handshaking entre "diferentes saltos" (por ejemplo, CA y el servidor) para cada conexión nueva, creo que Keep-Alive puede no ser aplicable en el contexto de SSL. Entonces, esa puede ser la razón por la cual el encabezado Keep-Alive se ignora usando conexiones HTTPS. En base a esta pregunta , es posible que deba asegurarse de que se use una instancia de conexión HTTP para garantizar la observación de Keep-Alive . Además, en la pregunta, parece que Apache HTTPClient ha sido una mejor solución.


intenta agregar el siguiente código:

con.setRequestProperty("Connection", "Keep-Alive"); con.setRequestProperty("Keep-Alive", "header");