Sube imágenes con la API de Publishing de los Servicios de juego de Play

La API de Play Games Services Publishing te permite subir una imagen para un recurso de juego.

Opciones de carga

La API de Play Games Services Publishing te permite subir ciertos tipos de datos binarios o multimedia. Las características específicas de los datos que puedes subir se describen en la página de referencia de cualquier método compatible con cargas de contenido multimedia:

  • Tamaño máximo de carga de archivos: La cantidad máxima de datos que puedes almacenar con este método

  • Tipos de MIME multimedia aceptados: Los tipos de datos binarios que puedes almacenar con este método

Puedes realizar solicitudes de carga de cualquiera de las siguientes maneras. Especifica el método que estás usando con el parámetro de solicitud uploadType.

  • Carga simple: uploadType=media. Se usa para lograr una transferencia rápida de archivos más pequeños, por ejemplo, de 5 MB o menos.

  • Carga multiparte: uploadType=multipart. Se usa para lograr una transferencia rápida de metadatos y archivos más pequeños; se transfiere el archivo junto con metadatos que lo describen, todo en una misma solicitud.

  • Carga reanudable: uploadType=resumable. Se usa para una lograr transferencia confiable; es importante en particular para archivos más grandes. Con este método, usas una solicitud de inicio de sesión, que puede incluir metadatos. Esta es una buena estrategia para la mayoría de las apps, ya que también funciona para archivos más pequeños al costo de una solicitud HTTP adicional por carga.

Cuando subes contenido multimedia, usas un URI especial. De hecho, los métodos compatibles con cargas de contenido multimedia tienen dos extremos de URI:

  • El URI /upload para el contenido multimedia. El formato del extremo de carga es el URI de recurso estándar con el prefijo "/upload". Cuando transfieras los datos del contenido multimedia, usa este URI

    Ejemplo: POST /upload/games/v1configuration/images/resourceId/imageType/imageType

  • El URI de recurso estándar para los metadatos. Si el recurso contiene campos de datos, estos se usan para almacenar metadatos que describen el archivo subido. Cuando crees o actualices valores de metadatos, puedes usar este URI.

    Ejemplo: POST /games/v1configuration/images/resourceId/imageType/imageType

Carga simple

El método más sencillo para subir un archivo es realizar una solicitud de carga simple. Esta es una buena opción cuando se produce una de las siguientes situaciones:

  • Cuando el archivo es demasiado pequeño como para volver a subirlo por completo si falla la conexión

  • Si no hay metadatos para enviar (esto podría ocurrir si tienes pensado enviar metadatos para este recurso en una solicitud independiente o si no se admiten metadatos o estos no están disponibles) Para usar una carga simple, realiza una solicitud POST o PUT al URI /upload del método y agrega el parámetro de consulta uploadType=media. Por ejemplo:

POST https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=media

Entre los encabezados HTTP que se deben usar cuando se realiza una solicitud de carga simple, se incluyen los siguientes:

  • Content-Type. Se establece como uno de los tipos de datos multimedia de la carga aceptados del método, según se especifica en la referencia de la API de Publishing.

  • Content-Length. Se establece como la cantidad de bytes que estás subiendo. No es obligatorio si usas la codificación de transferencia fragmentada.

Ejemplo: Carga simple

En el siguiente ejemplo, se muestra el uso de una solicitud de carga simple para la API de Play Games Services Publishing.

POST /upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=media HTTP/1.1
Host: www.googleapis.com
Content-Type: image/png
Content-Length: number_of_bytes_in_file
Authorization: Bearer your_auth_token

PNG data

Si la solicitud se realiza correctamente, el servidor muestra el código de estado HTTP 200 OK junto con los metadatos. Por ejemplo:

HTTP/1.1 200
Content-Type: application/json

{
  "kind": "gamesConfiguration#imageConfiguration",
  "url": string,
  "resourceId": string,
  "imageType": string
}

Carga multiparte

Si tienes metadatos que deseas enviar junto con los datos que vas a subir, puedes realizar una única solicitud multipart/related. Esta es una buena opción si los datos que vas a enviar son lo suficientemente pequeños como para volver a subirlos por completo si falla la conexión.

Para usar una carga multiparte, realiza una solicitud POST o PUT al URI /upload del método y agrega el parámetro de consulta uploadType=multipart. Por ejemplo:

POST https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=multipart

Entre los encabezados HTTP de nivel superior que se deben usar cuando se realiza una solicitud de carga multiparte, se incluyen los siguientes:

-Content-Type. Se establece como multiparte/relacionado; incluye la string de límite que usas para identificar las partes de la solicitud.

-Content-Length. Se establece como la cantidad total de bytes en el cuerpo de la solicitud. La parte de contenido multimedia de la solicitud debe ser menor que el tamaño de archivo máximo especificado para este método.

El cuerpo de la solicitud tiene el formato de un tipo de contenido multipart/related RFC2387 y contiene exactamente dos partes. Las partes se identifican mediante una string de límite, y la última string va seguida de dos guiones.

Cada parte de la solicitud multiparte necesita un encabezado Content-Type adicional:

  • Parte de metadatos: Debe colocarse primero, y Content-Type debe coincidir con uno de los formatos de metadatos aceptados.

  • Parte de contenido multimedia: Debe ir en segundo lugar, y Content-Type debe coincidir con uno de los tipos MIME multimedia aceptados del método.

Consulta la referencia de la API de Publishing para conocer la lista de tipos de MIME multimedia aceptados de cada método y los límites de tamaño de los archivos subidos.

Ejemplo: Carga multiparte

En el siguiente ejemplo, se muestra una solicitud de carga multiparte para la API de Play Games Services Publishing.

POST /upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=multipart HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer your_auth_token
Content-Type: multipart/related; boundary=foo_bar_baz
Content-Length: number_of_bytes_in_entire_request_body

--foo_bar_baz
Content-Type: application/json; charset=UTF-8

{
  "kind": "gamesConfiguration#imageConfiguration",
  "url": string,
  "resourceId": string,
  "imageType": string
}

--foo_bar_baz
Content-Type: image/png

PNG data
--foo_bar_baz--

Si la solicitud se realiza correctamente, el servidor muestra el código de estado HTTP 200 OK junto con los metadatos:

HTTP/1.1 200
Content-Type: application/json

{
  "kind": "gamesConfiguration#imageConfiguration",
  "url": string,
  "resourceId": string,
  "imageType": string
}

Carga reanudable

Para subir archivos de datos de manera más confiable, puedes usar el protocolo de carga reanudable. Con este protocolo, puedes reanudar una operación de carga si una falla de comunicación interrumpe el flujo de datos. Esto resulta particularmente útil cuando transfieres archivos de gran tamaño, y existe una alta probabilidad de que se interrumpa la conexión de red o de que se genere cualquier otra falla de transmisión, como puede ocurrir, por ejemplo, cuando subes archivos desde una app cliente para dispositivos móviles. Además, permite reducir tu uso de ancho de banda ante fallas de red, ya que no necesitas reiniciar la carga de archivos grandes desde el principio.

A continuación se indican los pasos para usar cargas reanudables:

  1. Inicia una sesión reanudable. Realiza una solicitud inicial al URI de carga que incluya los metadatos, si corresponde.

  2. Guarda el URI de la sesión reanudable. Guarda el URI de la sesión que se muestra en la respuesta de la solicitud inicial; lo usarás para las solicitudes restantes de esta sesión. Sube el archivo.

  3. Envía el archivo multimedia al URI de la sesión reanudable.

Además, las apps que usan cargas reanudables deben tener código para reanudar una carga interrumpida. Si se interrumpe una carga, averigua cuántos datos se recibieron de forma correcta y, a continuación, reanuda la carga desde ese punto.

Inicia una sesión reanudable

Para iniciar una carga reanudable, realiza una solicitud POST o PUT al URI /upload del método y agrega el parámetro de consulta uploadType=resumable. Por ejemplo:

POST https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=resumable

Para esta solicitud de inicio, el cuerpo está vacío o contiene solo los metadatos; la transferencia del contenido real del archivo que desees subir se llevará a cabo en solicitudes posteriores.

Usa los siguientes encabezados HTTP con la solicitud inicial:

  • X-Upload-Content-Type. Se establece como el tipo de MIME multimedia de los datos de carga que se transferirán en solicitudes posteriores.

  • X-Upload-Content-Length. Se establece como la cantidad de bytes de datos de carga que se transferirán en solicitudes posteriores. Si no se conoce el valor en el momento en que se realiza la solicitud, puedes omitir este encabezado.

  • Content-Type (si se proporcionan metadatos). Se establece de acuerdo con el tipo de datos de los metadatos.

  • Content-Length. Se establece como la cantidad de bytes proporcionada en el cuerpo de esta solicitud inicial. No es obligatorio si usas la codificación de transferencia fragmentada.

Consulta la referencia de la API de Publishing para conocer la lista de tipos de MIME multimedia aceptados de cada método y los límites de tamaño de los archivos subidos.

Ejemplo: Solicitud de inicio de sesión reanudable

En el siguiente ejemplo, se muestra cómo iniciar una sesión reanudable para la API de Play Games Services Publishing.

POST /upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=resumable HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer your_auth_token
Content-Length: 38
Content-Type: application/json; charset=UTF-8
X-Upload-Content-Type: image/png
X-Upload-Content-Length: 2000000

{
  "kind": "gamesConfiguration#imageConfiguration",
  "url": string,
  "resourceId": string,
  "imageType": string
}

En la próxima sección, se describe cómo manejar la respuesta.

Guarda el URI de la sesión reanudable

Si la solicitud de inicio de sesión se realiza correctamente, el servidor de la API responde con un código de estado HTTP 200 OK. Además, proporciona un encabezado Location que especifica el URI de la sesión reanudable. El encabezado Location, que se muestra en el siguiente ejemplo, incluye una parte del parámetro de consulta upload_id que proporciona el ID de carga único que se debe usar en esta sesión.

Ejemplo: Respuesta de inicio de sesión reanudable

A continuación se muestra la respuesta a la solicitud presentada en el Paso 1:

HTTP/1.1 200 OK
Location: https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=resumable&upload_id=xa298sd_sdlkj2
Content-Length: 0

El valor del encabezado Location, como se muestra en la respuesta de ejemplo anterior, es el URI de sesión que usarás como extremo HTTP para subir el archivo o consultar el estado de carga.

Copia y guarda este URI de sesión para poder usarlo en solicitudes posteriores.

Sube el archivo

Para subir el archivo, envía una solicitud PUT al URI de carga que obtuviste en el paso anterior. El formato de la solicitud de carga es el siguiente:

PUT session_uri

Los encabezados HTTP que se deben usar cuando se realizan solicitudes de carga de archivos reanudables incluyen Content-Length. Configura esta opción como la cantidad de bytes que subirás en esta solicitud, que suele ser el tamaño del archivo de la carga.

Ejemplo: Solicitud de carga de archivo reanudable

Esta es una solicitud reanudable para subir el archivo PNG de 2,000,000 bytes del ejemplo actual.

PUT https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=resumable&upload_id=xa298sd_sdlkj2 HTTP/1.1
Content-Length: 2000000
Content-Type: image/png

bytes 0-1999999

Si la solicitud se realiza correctamente, el servidor responde con HTTP 201 Created, además de todos los metadatos asociados a ese recurso. Si la solicitud inicial de la sesión reanudable hubiera sido PUT, para actualizar un recurso existente, la respuesta que indica que se realizó correctamente habría sido 200 OK, junto con todos los metadatos asociados a este recurso.

Si se interrumpe la solicitud de carga, o si recibes una respuesta HTTP 503 Service Unavailable o cualquier otra respuesta 5xx del servidor, sigue el procedimiento que se detalla en la sección Reanuda una carga interrumpida.


Sube el archivo en fragmentos

Con las cargas reanudables, puedes dividir un archivo en fragmentos y enviar diferentes solicitudes para subir cada fragmento en secuencia. No se recomienda este enfoque, ya que las solicitudes adicionales tienen costos de rendimiento asociados y, por lo general, no son necesarias. Sin embargo, es posible que necesites usar la fragmentación para reducir la cantidad de datos que se transfieren en una misma solicitud. Esto es útil cuando hay un límite de tiempo fijo para las solicitudes individuales, como ocurre con ciertas clases de solicitudes de Google App Engine. Además, te permite realizar acciones como proporcionar indicaciones del progreso de una carga en los navegadores heredados que no cuentan de forma predeterminada con asistencia de progreso de carga.

Si subes los datos como fragmentos, también debes incorporar el encabezado Content-Range, además de Content-Length, que se requiere para las cargas de archivos completos:

  • Content-Length: Se establece como el tamaño de fragmento, o posiblemente menos, como podría ser en el caso de la última solicitud.

  • Content-Range: Se establece para que muestre qué bytes del archivo estás subiendo. Por ejemplo, Content-Range: bytes 0-524287/2000000 muestra que estás subiendo los primeros 524,288 bytes (256 x 1024 x 2) de un archivo de 2,000,000 bytes.

Ejemplo: Solicitud de carga reanudable de un archivo en partes

Una solicitud que envía los primeros 524,288 bytes debería verse de esta manera:

PUT {session_uri} HTTP/1.1
Host: www.googleapis.com
Content-Length: 524288
Content-Type: image/png
Content-Range: bytes 0-524287/2000000

bytes 0-524288

Si la solicitud se realiza correctamente, el servidor responde con el encabezado 308 Resume Incomplete, junto con Range, que identifica la cantidad total de bytes que se almacenaron hasta el momento:

HTTP/1.1 308 Resume Incomplete
Content-Length: 0
Range: bytes=0-524287

Usa el valor superior que se muestra en el encabezado Range para determinar dónde comenzar el siguiente fragmento. Sigue ejecutando solicitudes PUT para cada fragmento hasta que el archivo se haya subido por completo.

Si se interrumpe la solicitud PUT de cualquier fragmento, o si recibes una respuesta HTTP 503 Service Unavailable o cualquier otra 5xx del servidor, sigue el procedimiento que se describe en la sección Reanuda una carga interrumpida, pero en lugar de subir el resto del archivo, continúa subiendo los fragmentos desde ese punto.

Notas importantes:

  • Asegúrate de usar el encabezado Range en la respuesta para determinar dónde comenzar el próximo fragmento; no supongas que el servidor recibió todos los bytes que se enviaron en la solicitud anterior.

  • Cada URI de carga tiene una vida útil limitada y finalmente vence (en el transcurso aproximado de un día si no se usa). Por este motivo, se recomienda que inicies la carga reanudable no bien obtengas el URI de carga y reanudes la carga interrumpida apenas después de la interrupción.

  • Si envías una solicitud con un ID de sesión de carga que ya venció, el servidor muestra un código de estado 404 Not Found. Cuando se produce un error irrecuperable en la sesión de carga, el servidor muestra un código de estado 410 Gone. En estos casos, debes iniciar una nueva carga reanudable, obtener un nuevo URI de carga y, luego, iniciar la carga desde el principio con el extremo nuevo.

Cuando se completa la carga del archivo, el servidor responde con HTTP 201 Created junto con los metadatos asociados a este recurso. En el caso de que la solicitud hubiera estado actualizando una entidad existente en lugar de crear una nueva, el código de respuesta HTTP para una carga completa habría sido 200 OK.


Reanuda una carga interrumpida

Si una solicitud de carga se interrumpe antes de que recibas una respuesta, o si recibes una respuesta HTTP 503 Service Unavailable del servidor, debes reanudar la carga interrumpida. Para reanudar una carga interrumpida, haz lo siguiente:

  1. Estado de la solicitud. Envía una solicitud PUT vacía al URI de carga para consultar el estado actual de la carga. En esta solicitud, los encabezados HTTP deben incluir un encabezado Content-Range que indique que se desconoce la posición actual en el archivo. Por ejemplo, configura Content-Range como */2000000 si el tamaño total del archivo es 2,000,000. Si no sabes la longitud total del archivo, configura Content-Range como */*.

  2. Consulta la cantidad de bytes subidos. Procesa la respuesta de la consulta de estado. El servidor usa el encabezado Range en su respuesta para especificar qué bytes recibió hasta el momento. Por ejemplo, un encabezado Range de 0-299999 indica que se recibieron los primeros 300,000 bytes del archivo.

  3. Sube los datos restantes. Por último, ahora que sabes dónde reanudar la solicitud, envía los datos restantes o el fragmento actual. Ten en cuenta que, en cualquiera de esos casos, debes tratar los datos restantes como fragmentos separados, por lo que tendrás que enviar el encabezado Content-Range cuando reanudes la carga.

Ejemplo: Cómo reanudar una carga interrumpida

  1. Solicita el estado de la carga. La siguiente solicitud utiliza el encabezado Content-Range para indicar que la posición actual en el archivo de 2,000,000 bytes es desconocida.

    PUT {session_uri} HTTP/1.1
    Content-Length: 0
    Content-Range: bytes */2000000
    
  2. Extrae de la respuesta la cantidad de bytes subidos hasta el momento. En la respuesta del servidor, se usa el encabezado Range para indicar que se recibieron los primeros 43 bytes del archivo hasta el momento. Utiliza el valor superior del encabezado Range para determinar dónde comenzar la carga reanudada.

HTTP/1.1 308 Resume Incomplete
Content-Length: 0
Range: 0-42
  1. Reanuda la carga desde el punto en que se interrumpió. La siguiente solicitud reanuda la carga; para ello, envía los bytes restantes del archivo a partir del byte 43.
PUT {session_uri} HTTP/1.1
Content-Length: 1999957
Content-Range: bytes 43-1999999/2000000

bytes 43-1999999

Prácticas recomendadas

Cuando subas contenido multimedia, es útil tener en cuenta algunas de las prácticas recomendadas relacionadas con el manejo de errores:

  • Reanuda o vuelve a intentar cargas que no se realizaron correctamente debido a interrupciones en la conexión o cualquier error 5xx, entre los que se incluyen los siguientes:

    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
  • Cuando reanudes o reintentes solicitudes de carga, usa una estrategia de retirada exponencial si se muestra cualquier error de servidor 5xx. Estos errores pueden ocurrir si se está sobrecargando un servidor. La retirada exponencial puede ayudarte a aliviar este tipo de problemas durante períodos de gran volumen de solicitudes o tráfico de red intenso.

  • No se deben manejar otros tipos de solicitudes mediante retirada exponencial, pero igual puedes reintentar varias de ellas. Cuando reintentes estas solicitudes, limita la cantidad de veces que lo haces. Por ejemplo, tu código podría limitarse a diez reintentos o menos antes de informar un error.

  • Maneja los errores 404 Not Found y 410 Gone cuando realices cargas reanudables; para ello, vuelve a iniciar toda la carga desde el principio.

Retirada exponencial

La retirada exponencial es una estrategia estándar de manejo de errores para aplicaciones de red en la que el cliente reintenta periódicamente una solicitud con fallas durante un período creciente. Si el servidor muestra errores debido a un gran volumen de solicitudes o tráfico de red intenso, la retirada exponencial puede ser una buena estrategia para manejar esos errores. Por el contrario, no se recomienda esta estrategia para ocuparse de errores que no están relacionados con el volumen de la red ni los tiempos de respuesta, como credenciales de autorización no válidas o errores de archivos no encontrados.

Si se la utiliza de forma correcta, la retirada exponencial aumenta la eficiencia del uso del ancho de banda, reduce la cantidad de solicitudes que se requieren para obtener una respuesta correcta y maximiza la capacidad de procesamiento de solicitudes en entornos simultáneos.

A continuación se muestra el flujo para implementar una retirada exponencial simple:

  1. Realizar una solicitud a la API
  2. Recibir una respuesta HTTP 503, que indica que debes reintentar la solicitud
  3. Esperar 1 segundo + random_number_milliseconds y reintentar la solicitud
  4. Recibir una respuesta HTTP 503, que indica que debes reintentar la solicitud
  5. Esperar 2 segundos + random_number_milliseconds y reintentar la solicitud
  6. Recibir una respuesta HTTP 503, que indica que debes reintentar la solicitud
  7. Esperar 4 segundos + random_number_milliseconds y reintentar la solicitud
  8. Recibir HTTP 503 response, que indica que debes reintentar la solicitud
  9. Esperar 8 segundos + random_number_milliseconds y reintentar la solicitud
  10. Recibir HTTP 503 response, que indica que debes reintentar la solicitud
  11. Esperar 16 segundos + random_number_milliseconds y reintentar la solicitud
  12. Detener; informar o registrar un error

En la lista anterior, random_number_milliseconds es una cantidad aleatoria de milisegundos menor o igual que 1,000. Este tiempo es necesario, ya que agregar un pequeño retraso aleatorio ayuda a distribuir la carga de manera más uniforme y a evitar la posibilidad de fallas en cascada en el servidor. El valor de random_number_milliseconds se debe volver a definir después de cada espera.

El algoritmo está configurado para terminar cuando n sea 5. Este límite impide que los clientes reintenten las solicitudes de forma infinita y genera una demora total de alrededor de 32 segundos antes de que una solicitud se considere "un error irrecuperable". Un límite más alto de reintentos es aceptable, sobre todo si hay una carga larga en progreso. Solo asegúrate de limitar la demora de reintentos a un valor razonable, por ejemplo, menos de un minuto.

Guías de la biblioteca cliente de la API