ID de región
El REGION_ID
es un código abreviado que Google asigna en función de la región que selecciones al crear tu aplicación. El código no corresponde a un país o provincia, aunque algunos IDs de región pueden parecerse a los códigos de país y provincia que se usan habitualmente. En las aplicaciones creadas después de febrero del 2020, REGION_ID.r
se incluye en las URLs de App Engine. En las aplicaciones creadas antes de esa fecha, el ID de región es opcional en la URL.
En este documento se describe cómo recibe solicitudes y envía respuestas tu aplicación de App Engine.
Para obtener más información, consulta la referencia de encabezados de solicitud y respuestas.
Si tu aplicación usa servicios, puedes dirigir las solicitudes a un servicio específico o a una versión específica de ese servicio. Para obtener más información sobre la disponibilidad de las direcciones de servicio, consulta Cómo se enrutan las solicitudes.
Gestionar solicitudes
Tu aplicación se encarga de iniciar un servidor web y de gestionar las solicitudes. Puedes usar cualquier framework web que esté disponible para tu lenguaje de desarrollo.
Cuando App Engine recibe una solicitud web para tu aplicación, invoca el servlet que corresponde a la URL, tal como se describe en el archivo web.xml
de la aplicación en el directorio WEB-INF/
.
Admite las especificaciones de la API Java Servlet 2.5 o 3.1 para proporcionar los datos de la solicitud al servlet y aceptar los datos de la respuesta.
App Engine ejecuta varias instancias de tu aplicación. Cada instancia tiene su propio servidor web para gestionar las solicitudes. Cualquier solicitud se puede enrutar a cualquier instancia, por lo que las solicitudes consecutivas del mismo usuario no se envían necesariamente a la misma instancia. El número de instancias se puede ajustar automáticamente a medida que cambia el tráfico.
De forma predeterminada, cada servidor web procesa las solicitudes de una en una. Para enviar varias solicitudes a cada servidor web en paralelo, marca tu aplicación como segura para subprocesos añadiendo un elemento <threadsafe>true</threadsafe>
al archivo appengine-web.xml
.
La siguiente clase de servlet de ejemplo muestra un mensaje sencillo en el navegador del usuario.
Cuotas y límites
App Engine asigna automáticamente recursos a tu aplicación a medida que aumenta el tráfico. Sin embargo, está sujeta a las siguientes restricciones:
App Engine reserva capacidad de escalado automático para las aplicaciones con baja latencia, en las que la aplicación responde a las solicitudes en menos de un segundo.
Las aplicaciones que dependen mucho de la CPU también pueden incurrir en una latencia adicional para compartir recursos de forma eficiente con otras aplicaciones en los mismos servidores. Las solicitudes de archivos estáticos están exentas de estos límites de latencia.
Cada solicitud entrante a la aplicación se incluye en el límite de solicitudes. Los datos enviados en respuesta a una solicitud se tienen en cuenta para el límite de ancho de banda saliente (facturable).
Tanto las solicitudes HTTP como las HTTPS (seguras) se contabilizan en los límites de Solicitudes, Ancho de banda de entrada (facturable) y Ancho de banda de salida (facturable). La página Detalles de la cuota de la Google Cloud consola también muestra los valores de Solicitudes seguras, Ancho de banda de entrada seguro y Ancho de banda de salida seguro por separado a modo informativo. Solo las solicitudes HTTPS se contabilizan en estos valores. Para obtener más información, consulta la página Cuotas.
Los siguientes límites se aplican específicamente al uso de controladores de solicitudes:
Límite | Cantidad |
---|---|
Tamaño de la solicitud | 32 megabytes |
Tamaño de la respuesta | 32 megabytes |
Tiempo de espera de solicitud | Depende del tipo de escalado que use tu aplicación |
Número total máximo de archivos (archivos de aplicaciones y archivos estáticos) | 10.000 en total 1000 por directorio |
Tamaño máximo de un archivo de aplicación | 32 megabytes |
Tamaño máximo de un archivo estático | 32 megabytes |
Tamaño total máximo de todos los archivos estáticos y de la aplicación | El primer gigabyte es gratuito 0,026 USD por gigabyte al mes después del primer gigabyte |
Tiempo de espera de las solicitudes pendientes | 10 segundos |
Tamaño máximo de un único campo de encabezado de solicitud | 8 kilobytes para los runtimes de segunda generación en el entorno estándar. Las solicitudes a estos tiempos de ejecución con campos de encabezado que superen los 8 kilobytes devolverán errores HTTP 400. |
Límites de solicitudes
Todas las solicitudes HTTP/2 se traducirán a solicitudes HTTP/1.1 cuando se reenvíen al servidor de aplicaciones.
Límites de respuesta
Las respuestas dinámicas tienen un límite de 32 MB. Si un controlador de secuencias de comandos genera una respuesta que supera este límite, el servidor devuelve una respuesta vacía con el código de estado 500 Internal Server Error. Esta limitación no se aplica a las respuestas que proporcionan datos del antiguo Blobstore o de Cloud Storage.
El límite de encabezados de respuesta es de 8 KB para los runtimes de segunda generación. Los encabezados de respuesta que superen este límite devolverán errores HTTP 502 y los registros mostrarán
upstream sent too big header while reading response header from upstream
.
Encabezados de solicitud
Una solicitud HTTP entrante incluye las cabeceras HTTP enviadas por el cliente. Por motivos de seguridad, los proxies intermedios anonimizan o modifican algunos encabezados antes de que lleguen a la aplicación.
Para obtener más información, consulta la referencia de encabezados de solicitud.
Gestionar los tiempos de espera de las solicitudes
App Engine está optimizado para aplicaciones con solicitudes de corta duración, normalmente las que tardan unos cientos de milisegundos. Una aplicación eficiente responde rápidamente a la mayoría de las solicitudes. Una aplicación que no lo haga no se escalará bien con la infraestructura de App Engine. Para asegurar este nivel de rendimiento, el sistema impone un tiempo de espera máximo de las solicitudes al que deben responder todas las aplicaciones.
Si tu aplicación supera este plazo, App Engine interrumpe el controlador de solicitudes. El entorno de tiempo de ejecución de Java interrumpe el servlet lanzando unacom.google.apphosting.api.DeadlineExceededException
.
Si no hay ningún controlador de solicitudes que detecte esta excepción, el entorno de tiempo de ejecución devolverá un error de servidor HTTP 500 al cliente.
Si hay un controlador de solicitudes y se detecta DeadlineExceededException
, el entorno de tiempo de ejecución da al controlador de solicitudes un tiempo (menos de un segundo) para preparar una respuesta personalizada. Si el controlador de solicitudes tarda más de un segundo después de generar la excepción en preparar una respuesta personalizada, se generará un HardDeadlineExceededError
.
Tanto DeadlineExceededExceptions
como HardDeadlineExceededErrors
forzarán la finalización de la solicitud y detendrán la instancia.
Para saber cuánto tiempo queda antes de la fecha límite, la aplicación puede
importar
com.google.apphosting.api.ApiProxy
y llamar a
ApiProxy.getCurrentEnvironment().getRemainingMillis()
.
Esto resulta útil si la aplicación tiene previsto empezar a realizar alguna tarea que pueda tardar demasiado. Si sabes que se tarda cinco segundos en procesar una unidad de trabajo, pero getRemainingMillis()
devuelve menos tiempo, no tiene sentido empezar esa unidad de trabajo.
Respuestas
App Engine llama al servlet con un objeto de solicitud y un objeto de respuesta. A continuación, espera a que el servlet rellene el objeto de respuesta y lo devuelva. Cuando el servlet devuelve los resultados, los datos del objeto de respuesta se envían al usuario.Hay límites de tamaño que se aplican a la respuesta que generas, y la respuesta se puede modificar antes de devolverse al cliente.
Para obtener más información, consulta la referencia de respuestas de solicitudes.Respuestas de streaming
App Engine no admite respuestas de streaming en las que los datos se envían en fragmentos incrementales al cliente mientras se procesa una solicitud. Todos los datos de tu código se recogen tal como se ha descrito anteriormente y se envían como una única respuesta HTTP.
Compresión de respuestas
App Engine hace todo lo posible para servir contenido comprimido (gzipeado) a los clientes que lo admiten. Para determinar si se debe comprimir el contenido, App Engine hace lo siguiente cuando recibe una solicitud:Confirma si el cliente puede recibir respuestas comprimidas de forma fiable consultando los encabezados
Accept-Encoding
yUser-Agent
de la solicitud. De esta forma, se evitan algunos errores conocidos con el contenido comprimido con gzip en navegadores populares.Confirma si es adecuado comprimir el contenido consultando el encabezado
Content-Type
que has configurado para el controlador de respuestas. Por lo general, la compresión es adecuada para los tipos de contenido basados en texto, pero no para los tipos de contenido binario.
Ten en cuenta lo siguiente:
Un cliente puede forzar la compresión de los tipos de contenido basados en texto si asigna el valor
gzip
a los encabezados de solicitudAccept-Encoding
yUser-Agent
.Si una solicitud no especifica
gzip
en el encabezadoAccept-Encoding
, App Engine no comprimirá los datos de la respuesta.El frontend de Google almacena en caché las respuestas de los controladores de archivos estáticos y directorios de App Engine. En función de varios factores, como el tipo de datos de respuesta que se almacena en caché primero, los encabezados
Vary
que hayas especificado en la respuesta y los encabezados que se incluyan en la solicitud, un cliente podría solicitar datos comprimidos, pero recibir datos sin comprimir, y viceversa. Para obtener más información, consulta Almacenamiento en caché de respuestas.
Almacenamiento en caché de respuestas
El frontend de Google, y posiblemente el navegador del usuario y otros servidores proxy de almacenamiento en caché intermedios, almacenarán en caché las respuestas de tu aplicación según las instrucciones de los encabezados de almacenamiento en caché estándar que especifiques en la respuesta. Puede especificar estos encabezados de respuesta a través de su framework, directamente en su código o mediante los gestores de archivos y directorios estáticos de App Engine.
En el frontend de Google, la clave de caché es la URL completa de la solicitud.
Almacenar contenido estático en caché
Para asegurarte de que los clientes siempre reciban contenido estático actualizado en cuanto se publique, te recomendamos que sirvas contenido estático desde directorios con versiones, como css/v1/styles.css
. El frontend de Google no validará la caché (comprobará si hay contenido actualizado) hasta que caduque. Aunque la caché caduque, no se actualizará hasta que cambie el contenido de la URL de la solicitud.
Los siguientes encabezados de respuesta que puedes
definir en
appengine-web.xml
influyen en cómo y cuándo almacena en caché el contenido el frontend de Google:
Cache-Control
debe tener el valorpublic
para que Google Frontend pueda almacenar contenido en caché. También puede almacenarse en caché en Google Frontend a menos que especifiques una directivaCache-Control
private
ono-store
. Si no defines este encabezado enappengine-web.xml
, App Engine lo añade automáticamente a todas las respuestas gestionadas por un controlador de archivos o directorios estáticos. Para obtener más información, consulta el artículo sobre encabezados añadidos o sustituidos.Vary
: para que la caché devuelva respuestas diferentes para una URL en función de los encabezados que se envíen en la solicitud, defina uno o varios de los siguientes valores en el encabezado de respuestaVary
:Accept
,Accept-Encoding
,Origin
oX-Origin
.Debido a la alta cardinalidad potencial, los datos no se almacenarán en caché para otros valores de
Vary
.Por ejemplo:
Especifica el siguiente encabezado de respuesta:
Vary: Accept-Encoding
Tu aplicación recibe una solicitud que contiene el encabezado
Accept-Encoding: gzip
. App Engine devuelve una respuesta comprimida y el frontend de Google almacena en caché la versión comprimida con gzip de los datos de la respuesta. Todas las solicitudes posteriores de esta URL que contengan el encabezadoAccept-Encoding: gzip
recibirán los datos comprimidos con gzip de la caché hasta que esta se invalide (porque el contenido cambie después de que caduque la caché).Tu aplicación recibe una solicitud que no contiene el encabezado
Accept-Encoding
. App Engine devuelve una respuesta sin comprimir y Google Frontend almacena en caché la versión sin comprimir de los datos de la respuesta. Todas las solicitudes posteriores de esta URL que no contengan el encabezadoAccept-Encoding
recibirán los datos comprimidos de la caché hasta que esta se invalide.
Si no especifica un encabezado de respuesta
Vary
, el frontend de Google crea una sola entrada de caché para la URL y la usará en todas las solicitudes, independientemente de los encabezados de la solicitud. Por ejemplo:- No especifica el encabezado de respuesta
Vary: Accept-Encoding
. - Una solicitud contiene la cabecera
Accept-Encoding: gzip
y se almacenará en caché la versión comprimida con gzip de los datos de la respuesta. - Una segunda solicitud no contiene el encabezado
Accept-Encoding: gzip
. Sin embargo, como la caché contiene una versión comprimida con gzip de los datos de respuesta, la respuesta se comprimirá con gzip aunque el cliente haya solicitado datos sin comprimir.
Los encabezados de la solicitud también influyen en el almacenamiento en caché:
- Si la solicitud contiene un encabezado
Authorization
, el contenido no se almacenará en la caché del frontend de Google.
Vencimiento de la caché
De forma predeterminada, los encabezados de almacenamiento en caché que los controladores de archivos estáticos y de directorios de App Engine añaden a las respuestas indican a los clientes y a los proxies web, como Google Frontend, que el caché caduque al cabo de 10 minutos.
Una vez que se ha transmitido un archivo con un tiempo de vencimiento determinado, por lo general, no hay forma de eliminarlo de las cachés de proxy web, aunque el usuario borre su propia caché del navegador. Al volver a implementar una nueva versión de la aplicación, no se restablecerá ninguna caché. Por lo tanto, si tienes previsto modificar un archivo estático, debe tener un tiempo de vencimiento corto (menos de una hora). En la mayoría de los casos, el tiempo de vencimiento predeterminado de 10 minutos es adecuado.
Puedes cambiar el vencimiento predeterminado de todos los controladores de archivos estáticos y directorios
especificando el elemento
static-files
en el archivo
appengine-web.xml
.
Almacenamiento de registros
Tu aplicación puede escribir información en los registros de la aplicación mediante java.util.logging.Logger. Los datos de registro de tu aplicación se pueden ver en la Google Cloud consola con Cloud Logging. A cada solicitud registrada se le asigna un ID de solicitud, un identificador único global basado en la hora de inicio de la solicitud. La consolaGoogle Cloud puede reconocer los niveles de registro de la claseLogger
y mostrar mensajes de forma interactiva en diferentes niveles.
Todo lo que el servlet escribe en el flujo de salida estándar (System.out
) y en el flujo de errores estándar (System.err
) lo captura App Engine y se registra en los registros de la aplicación. Las líneas escritas en el flujo de salida estándar se registran en el nivel "INFO", y las líneas escritas en el flujo de errores estándar se registran en el nivel "WARNING". Se puede usar cualquier framework de registro (como log4j) que registre datos en los flujos de salida o de errores. Sin embargo, para tener un control más preciso del nivel de registro que se muestra en la consola Google Cloud , el framework de registro debe usar un adaptador java.util.logging
.
El SDK de Java de App Engine incluye un archivo de plantilla logging.properties
en el directorio appengine-java-sdk/config/user/
. Para usarlo, copia el archivo en tu directorio WEB-INF/classes
(o en cualquier otro lugar del archivo WAR) y, a continuación, asigna el valor java.util.logging.config.file
a la propiedad del sistema "WEB-INF/logging.properties"
(o a la ruta que elijas, en relación con la raíz de la aplicación). Puedes definir propiedades del sistema en el archivo appengine-web.xml
de la siguiente manera:
El servlet registra mensajes con el nivel de registro INFO
(con log.info()
). El nivel de registro predeterminado es WARNING
, que suprime los mensajes INFO
de la salida. Para cambiar el nivel de registro, edita el archivo logging.properties
.
El entorno
Todas las propiedades del sistema y variables de entorno son privadas para tu aplicación. Definir una propiedad del sistema solo afecta a la vista de esa propiedad de tu aplicación, no a la vista de la JVM.Puedes definir propiedades del sistema y variables de entorno para tu aplicación en el descriptor de implementación.
App Engine define varias propiedades del sistema que identifican el entorno de tiempo de ejecución:
com.google.appengine.runtime.environment
es"Production"
cuando se ejecuta en App Engine y"Development"
cuando se ejecuta en el servidor de desarrollo.Además de usar
System.getProperty()
, puedes acceder a las propiedades del sistema mediante nuestra API con seguridad de tipos. Por ejemplo:if (SystemProperty.environment.value() == SystemProperty.Environment.Value.Production) { // The app is running on App Engine... }
com.google.appengine.runtime.version
es el ID de versión del entorno de tiempo de ejecución, como"1.3.0"
. Para obtener la versión, invoca lo siguiente:String version = SystemProperty.version.get();
com.google.appengine.application.id
es el ID de la aplicación. Para obtener el ID, invoca lo siguiente:String ID = SystemProperty.applicationId.get();
com.google.appengine.application.version
es la versión principal y secundaria del servicio de la aplicación que se está ejecutando, con el formato "X.Y". El número de versión principal ("X") se especifica en el archivoappengine-web.xml
del servicio. El número de versión secundaria ("Y") se asigna automáticamente cuando se sube cada versión de la aplicación a App Engine. Para obtener el ID, invoca lo siguiente:String ID = SystemProperty.applicationVersion.get();
En el servidor web de desarrollo, la versión principal devuelta siempre es la versión del servicio predeterminado y la versión secundaria siempre es "1".
App Engine también define las siguientes propiedades del sistema cuando inicializa la JVM en un servidor de aplicaciones:
file.separator
path.separator
line.separator
java.version
java.vendor
java.vendor.url
java.class.version
java.specification.version
java.specification.vendor
java.specification.name
java.vm.vendor
java.vm.name
java.vm.specification.version
java.vm.specification.vendor
java.vm.specification.name
user.dir
IDs de instancia
Puede obtener el ID de la instancia que gestiona una solicitud con este código:
com.google.apphosting.api.ApiProxy.getCurrentEnvironment().getAttributes().get("com.google.appengine.instance.id")
En el entorno de producción, un administrador que haya iniciado sesión puede usar el ID en una URL:
https://INSTANCE_ID-dot-VERSION_ID-dot-SERVICE_ID-dot-PROJECT_ID.REGION_ID.r.appspot.com
. La solicitud se dirigirá a esa instancia específica. Si la instancia no puede gestionar la solicitud, devuelve un error 503 inmediato.
IDs de solicitud
En el momento de la solicitud, puedes guardar el ID de solicitud, que es único para cada solicitud. El ID de solicitud se puede usar más adelante para relacionar una solicitud con los registros de esa solicitud.
En el siguiente código se muestra cómo obtener el ID de solicitud en el contexto de una solicitud:
com.google.apphosting.api.ApiProxy.getCurrentEnvironment().getAttributes().get("com.google.appengine.runtime.request_log_id")
Forzar las conexiones HTTPS
Por motivos de seguridad, todas las aplicaciones deben animar a los clientes a conectarse a través de https
. Para indicar al navegador que prefiera https
en lugar de http
en una página o en todo un dominio, define el encabezado Strict-Transport-Security
en tus respuestas.
Por ejemplo:
Strict-Transport-Security: max-age=31536000; includeSubDomains
La mayoría de los frameworks de aplicaciones y servidores web admiten la configuración de este encabezado
para las respuestas que se generan a partir de tu código. Para obtener información sobre la cabecera Strict-Transport-Security
en Spring Boot, consulta Seguridad de transporte estricta mediante HTTP (HSTS).
Gestionar el trabajo asíncrono en segundo plano
El trabajo en segundo plano es cualquier tarea que realiza tu aplicación para una solicitud después de haber enviado la respuesta HTTP. Evita realizar tareas en segundo plano en tu aplicación y revisa el código para asegurarte de que todas las operaciones asíncronas finalicen antes de enviar la respuesta.
Para los trabajos de larga duración, recomendamos usar Cloud Tasks. Con Cloud Tasks, las solicitudes HTTP son duraderas y solo devuelven una respuesta cuando finaliza el trabajo asíncrono.