Posible motivo de los códigos de error NGINX 499


116

Recibo muchos códigos de error 499 NGINX. Veo que este es un problema del lado del cliente. No es un problema con NGINX o mi pila uWSGI. Observo la correlación en los registros de uWSGI cuando obtengo un 499.

address space usage: 383692800 bytes/365MB} {rss usage: 167038976
bytes/159MB} [pid: 16614|app: 0|req: 74184/222373] 74.125.191.16 ()
{36 vars in 481 bytes} [Fri Oct 19 10:07:07 2012] POST /bidder/ =>
generated 0 bytes in 8 msecs (HTTP/1.1 200) 1 headers in 59 bytes (1
switches on core 1760)
SIGPIPE: writing to a closed pipe/socket/fd (probably the client
disconnected) on request /bidder/ (ip 74.125.xxx.xxx) !!!
Fri Oct 19 10:07:07 2012 - write(): Broken pipe [proto/uwsgi.c line
143] during POST /bidder/ (74.125.xxx.xxx)
IOError: write error

Estoy buscando una explicación más detallada y espero que no haya nada de malo en mi configuración de NGINX para uwsgi. Lo tomo por su valor nominal. Parece un problema de cliente.


¿Alguna vez encontró una solución a esto? Veo exactamente el mismo problema con uWSGI y nginx.
Raj

1
Lo obtengo cuando aborto una solicitud de jQuery ajax.
mpen

1
Sé que esta es una pregunta muy antigua, pero la cantidad de preguntas fuera de lugar en SO es asombrosa. Esto claramente pertenece a SF.
Sosukodo

Respuestas:


164

HTTP 499 en Nginx significa que el cliente cerró la conexión antes de que el servidor respondiera a la solicitud. En mi experiencia, generalmente se debe al tiempo de espera del lado del cliente . Como sé, es un código de error específico de Nginx.


1
Como caso especial, noté que a veces sucede cuando el usuario final hace doble clic en el botón de envío de un formulario. El formulario se envía dos veces, pero el cliente solo espera una respuesta. Esto se puede solucionar desactivando (al menos durante unos segundos) los botones en JS la primera vez que se hace clic en ellos.
Antoine Pinsard

14
Es importante tener en cuenta que el "cliente" en realidad podría ser un proxy. Por ejemplo, si está utilizando un equilibrador de carga, podría cancelar la solicitud al servidor nginx debido a un tiempo de espera.
Brad Koch

Sucede en mi APLICACIÓN Angular si el usuario cierra la pestaña y mis solicitudes de API no se completan.
Vivek Saurabh

Es importante tener en cuenta que esto también puede ser causado por el servidor ; si el servidor tarda demasiado en responder, el cliente se da por vencido.
ijoseph

78

En mi caso, estaba impaciente y terminé malinterpretando el registro.

De hecho, el problema real era la comunicación entre nginx y uwsgi, y no entre el navegador y nginx. Si hubiera cargado el sitio en mi navegador y hubiera esperado lo suficiente, habría obtenido un "504 - Bad Gateway". Pero tomó tanto tiempo que seguí probando cosas y luego actualicé en el navegador. Así que nunca esperé lo suficiente para ver el error 504. Cuando se actualiza en el navegador, es cuando se cierra la solicitud anterior, y Nginx escribe eso en el registro como 499.

Elaboración

Aquí asumiré que el lector sabe tan poco como yo cuando empecé a jugar.

Mi configuración era un proxy inverso, el servidor nginx y un servidor de aplicaciones, el servidor uWSGI detrás de él. Todas las solicitudes del cliente irían al servidor nginx, luego se enviarían al servidor uWSGI y luego se enviaría la respuesta de la misma manera. Creo que así es como todos usan nginx / uwsgi y se supone que deben usarlo.

Mi nginx funcionó como debería, pero algo andaba mal con el servidor uwsgi. Hay dos formas (tal vez más) en las que el servidor uwsgi puede fallar al responder al servidor nginx.

1) uWSGI dice: "Estoy procesando, solo espera y pronto recibirás una respuesta". nginx tiene un cierto período de tiempo, que está dispuesto a esperar, fx 20 segundos. Después de eso, responderá al cliente con un error 504.

2) uWSGI está muerto, o uWSGi muere mientras nginx lo está esperando. nginx lo ve de inmediato y, en ese caso, devuelve un error 499.

Estaba probando mi configuración haciendo solicitudes en el cliente (navegador). En el navegador no pasó nada, simplemente seguía colgando. Después de tal vez 10 segundos (menos que el tiempo de espera) concluí que algo no estaba bien (lo cual era cierto) y cerré el servidor uWSGI desde la línea de comando. Luego iría a la configuración de uWSGI, probaría algo nuevo y luego reiniciaría el servidor uWSGI. En el momento en que cerré el servidor uWSGI, el servidor nginx devolvería un error 499.

Así que seguí depurando con el error 499, lo que significa buscar en Google el error 499. Pero si hubiera esperado lo suficiente, habría obtenido el error 504. Si hubiera recibido el error 504, habría podido comprender mejor el problema y luego podría depurarlo.

Entonces, la conclusión es que el problema era con uWGSI, que seguía colgando ("Espera un poco más, solo un poco más, entonces tendré una respuesta para ti ...").

Cómo solucioné ese problema, no lo recuerdo. Supongo que podría deberse a muchas cosas.


1
¿Cómo terminaste resolviendo esto? Tengo el mismo problema y no he podido precisar la causa.
Colin Nichols

1
Agregué una elaboración, desafortunadamente, no creo que resuelva su problema.
Mads Skjern

1
¡Solo quería darte las gracias! Tuve exactamente la misma situación y esto me puso en el camino correcto.
Aaron

3
@Shafiul: Mi elaboración no explica qué causó el problema con uWSGI, simplemente explica que uWSGI fue la causa (y no nginx). La elaboración describe los síntomas y cómo los interpreté mal. Entiendo tu decepción, pero has entendido mal la esencia de mi respuesta. Sinceramente.
Mads Skjern

2
Respuesta extremadamente útil, ¡nunca la elimines! Estos conceptos deben desarrollarse en la documentación en algún lugar, ¡usted hace un gran servicio al explicar cómo se comporta de manera diferente a lo que implican los documentos!
jerclarke

21

¿El cliente cerró la conexión no significa que sea un problema del navegador? ¡De ningún modo!

Puede encontrar 499 errores en un archivo de registro si tiene un LB (equilibrador de carga) frente a su servidor web (nginx), ya sea AWS o haproxy (personalizado). Dicho esto, LB actuará como cliente de nginx.

Si ejecuta los valores predeterminados de haproxy para:

    timeout client  60000
    timeout server  60000

Eso significaría que LB expirará después de 60000ms si no hay respuesta de nginx. Pueden ocurrir tiempos de espera para sitios web ocupados o scripts que necesitan más tiempo para su ejecución. Necesitará encontrar un tiempo de espera que funcione para usted. Por ejemplo, extenderlo a:

    timeout client  180s
    timeout server  180s

Y probablemente estarás listo.

Dependiendo de su configuración, es posible que vea un error de tiempo de espera de puerta de enlace 504 en su navegador, lo que indica que algo está mal con php-fpm, pero ese no será el caso con errores 499 en sus archivos de registro.


12

Como señala 499un aborto de conexión registrado por el nginx. Pero generalmente esto se produce cuando su servidor backend está siendo demasiado lento y otro proxy se agota primero o el software del usuario aborta la conexión. Por lo tanto, verifique si uWSGI está respondiendo rápido o no o si hay alguna carga en uWSGI / servidor de base de datos.

En muchos casos, existen otros proxies entre el usuario y nginx. Algunos pueden estar en su infraestructura como tal vez un CDN, Load Balacer, un caché de Varnish, etc. Otros pueden estar en el lado del usuario como un proxy de almacenamiento en caché, etc.

Si hay proxies de su lado, como LoadBalancer / CDN ... debe establecer los tiempos de espera para que se agote primero su backend y progresivamente los otros proxies para el usuario.

Si usted tiene:

user >>> CDN >>> Load Balancer >>> Nginx >>> uWSGI

Te recomendaré que establezcas:

  • n segundos para el tiempo de espera de uWSGI
  • n+1 segundos para el tiempo de espera de nginx
  • n+2 segundos para el tiempo de espera de Load Balancer
  • n+3 segundos de tiempo de espera para el CDN.

Si no puede establecer algunos de los tiempos de espera (como CDN), busque cuál es su tiempo de espera y ajuste los demás de acuerdo con él ( n, n-1...).

Esto proporciona una cadena correcta de tiempos de espera. y encontrará quién da el tiempo de espera y devuelve el código de respuesta correcto al usuario.


8

En mi caso obtuve 499 cuando la API del cliente cerró la conexión antes de recibir alguna respuesta. Envió literalmente un POST y cierre inmediatamente la conexión. Esto se resuelve por opción:

proxy_ignore_client_abort en

Documento Nginx


3
No entiendo cómo ayuda esto
Vladimir Starkov

¿Quizás no sea tu caso? El cliente envía los datos y no le interesa lo que le ocurrirá y cuál será la respuesta. Pero mi aplicación debería procesar los datos. Sin esta opción, los datos simplemente no tienen tiempo de llegar a mi aplicación.
DerSkythe

Gracias. Síntomas exactos y solución perfecta.
TTimo

¡Guau! Eso es casi exactamente lo que necesito. Lo único que agregaría sería enviar 200 respuestas a la fuente del webhook un poco antes de que cierre la conexión. De lo contrario, tienden a deshabilitar los webhooks y no los vuelven a enviar ... ¿Puedo hacerlo para las URL seleccionadas?
Pilat

1
Esto no resuelve el problema de que su cliente no obtenga una respuesta. Solo elimina 499 errores en sus registros y los reemplaza con el código de estado 200. Es una mala idea hacer esto. La verdadera solución es decirle a su cliente que aumente su configuración de tiempo de espera ...
marcinx

7

Resulta que 499 realmente significa "conexión interrumpida por el cliente".

Tuve un tiempo de espera de lectura de cliente de 60 s (y nginx también tiene un proxy_read_timeout predeterminado de 60 s). Entonces, lo que estaba sucediendo en mi caso es que nginx produciría un error.log an upstream timed out (110: Connection timed out) while reading upstreamy luego nginx reintentaría "el siguiente servidor proxy en el grupo de servidores backend que configuró". Eso es si tienes más de uno.

Luego intenta el siguiente y el siguiente hasta que (por defecto ) los ha agotado todos. A medida que cada uno se agota, también los elimina de la lista de servidores backend "en vivo". Después de que todos están agotados, devuelve un504 gateway timeout.

Entonces, en mi caso, nginx marcó el servidor como "no disponible", lo volvió a intentar en el siguiente servidor, luego se 60sprodujo el tiempo de espera de mi cliente (inmediatamente), por lo que vería un upstream timed out (110: Connection timed out) while reading upstreamregistro, seguido inmediatamente por un registro 499. Pero fue solo una coincidencia de tiempo.

Relacionado:

Si todos los servidores del grupo están marcados como no disponibles actualmente, también devuelve un valor 502 Bad Gateway.de 10 segundos. Vea aquí max_fails y fail_timeout. En los troncos diráno live upstreams while connecting to upstream.

Si solo tiene un servidor proxy backend en su grupo de servidores, simplemente pruebe con el único servidor, y devuelve a 504 Gateway Time-outy no elimina el servidor único de la lista de servidores "en vivo", si proxy_read_timeoutes superado. Consulte aquí "Si solo hay un servidor en un grupo, los parámetros max_fails, fail_timeout y slow_start se ignoran, y dicho servidor nunca se considerará no disponible".

La parte realmente complicada es que si especifica proxy_pass a "localhost" y su caja también tiene ipv6 e ipv4 "versiones de ubicación" en él al mismo tiempo (la mayoría de las cajas lo hacen por defecto), contará como si tuviera una "lista" de varios servidores en su grupo de servidores, lo que significa que puede entrar en la situación anterior de que devuelva "502 por 10 segundos" aunque enumere sólo un servidor . Consulte aquí "Si un nombre de dominio se resuelve en varias direcciones, todas se utilizarán de forma rotatoria". Una solución es declararlo como proxy_pass http://127.0.0.1:5001;(su dirección ipv4) para evitar que sea tanto ipv6 como ipv4. Entonces cuenta como comportamiento de "un solo servidor".

Hay algunas configuraciones diferentes que puede modificar para hacer que esto sea un problema "menor". Como aumentar los tiempos de espera o hacer que no marque los servidores como "desactivados" cuando se agota el tiempo de espera ... o arreglar la lista para que sea solo de tamaño 1, ver arriba :)

Ver también: https://serverfault.com/a/783624/27813


3

Este error es bastante fácil de reproducir usando la configuración estándar de nginx con php-fpm.

Mantener presionado el botón F5 en una página creará docenas de solicitudes de actualización al servidor. Cada solicitud anterior es cancelada por el navegador en una nueva actualización. En mi caso, encontré docenas de 499 en el archivo de registro de la tienda en línea de mi cliente. Desde el punto de vista de nginx: si la respuesta no se ha entregado al cliente antes de la próxima solicitud de actualización, nginx registra el error 499.

mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:32 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:33 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:33 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:33 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:33 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:34 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:34 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:34 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:34 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:35 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:35 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)

Si el procesamiento de php-fpm tarda más (como una página de WP pesada), puede causar problemas, por supuesto. He oído hablar de fallas de php-fpm, por ejemplo, pero creo que se pueden evitar configurando los servicios correctamente, como manejar las llamadas a xmlrpc.php.


2

... vino aquí de una búsqueda en Google

Encontré la respuesta en otro lugar aquí -> https://stackoverflow.com/a/15621223/1093174

que era aumentar el tiempo de espera inactivo de la conexión de mi balanceador de carga elástico de AWS.

(Había configurado un sitio de Django con nginx / apache reverse proxy, y un trabajo / vista de backend de registro realmente se agotaba)


0

Una vez que obtuve 499 "La solicitud ha sido prohibida por antivirus" como una respuesta http de AJAX (falso positivo de Kaspersky Internet Security con un análisis heurístico ligero, un análisis heurístico profundo sabía correctamente que no había nada malo).


0

Encontré este problema y la causa se debió al complemento Kaspersky Protection en el navegador. Si se encuentra con esto, intente deshabilitar sus complementos y vea si eso soluciona su problema.


0

Una de las razones de este comportamiento podría ser que está usando httppara en uwsgilugar de socket. Utilice el siguiente comando si lo está utilizando uwsgidirectamente.

uwsgi --socket :8080 --module app-name.wsgi

El mismo comando en el archivo .ini es

chdir = /path/to/app/folder
socket = :8080
module = app-name.wsgi

0

Esto no responde a la pregunta de los OP, pero como terminé aquí después de buscar furiosamente una respuesta, quería compartir lo que descubrimos.

En nuestro caso, resulta que se esperan estos 499. Cuando los usuarios usan la función de escritura anticipada en algunos cuadros de búsqueda, por ejemplo, vemos algo como esto en los registros.

GET /api/search?q=h [Status 499] 
GET /api/search?q=he [Status 499]
GET /api/search?q=hel [Status 499]
GET /api/search?q=hell [Status 499]
GET /api/search?q=hello [Status 200]

Entonces, en nuestro caso, creo que es seguro de usar, lo proxy_ignore_client_abort onque se sugirió en una respuesta anterior. ¡Gracias por eso!



0

En mi caso, he configurado como

AWS ELB >> ECS(nginx) >> ECS(php-fpm).

Había configurado el grupo de seguridad de AWS incorrecto para el servicio ECS (php-fpm), por lo que Nginx no pudo comunicarse con el contenedor de tareas php-fpm. Es por eso que recibía errores en el registro de tareas de nginx

499 0 - elb-healthchecker/2.0

La verificación de estado se configuró para verificar el servicio php-fpm y confirmar que está activo y devolver una respuesta.


0

Sé que este es un hilo antiguo, pero coincide exactamente con lo que me sucedió recientemente y pensé en documentarlo aquí. La configuración (en Docker) es la siguiente:

  • nginx_proxy
  • nginx
  • php_fpm ejecutando la aplicación real.

El síntoma era un "502 Gateway Timeout" en el indicador de inicio de sesión de la aplicación. Examen de los registros encontrados:

  • el botón funciona a través de un HTTP POSTpara /login... y así ...
  • nginx-proxy obtuvo el /login solicitud y, finalmente, informó un tiempo de espera.
  • nginx devolvió una 499respuesta, que por supuesto significa "el host murió".
  • ¡La /loginsolicitud no apareció en absoluto (!) en los registros del servidor FPM.
  • no hubo rastreos o mensajes de error en FPM ... nada, zero, zippo, none.

Resultó que el problema era una falla al conectarse a la base de datos para verificar el inicio de sesión. Pero cómo averiguarlo resultó ser pura conjetura.

La ausencia total de registros de seguimiento de aplicaciones ... o incluso un registro de que FPM había recibido la solicitud ... fue una sorpresa completa (y devastadora ...) para mí. Sí, se supone que la aplicación registra fallas, pero en este caso parece que el proceso de trabajo de FPM murió con un error de tiempo de ejecución, lo que 499generó la respuesta de nginx. Ahora, esto obviamente es un problema en nuestra aplicación ... en alguna parte. Pero quería registrar los detalles de lo que sucedió para beneficio de las próximas personas que enfrentan algo como esto.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.