¿Qué significa "Content-type: application / json; charset = utf-8 "realmente significa?

284

Cuando hago una solicitud POST con un cuerpo JSON a mi servicio REST, lo incluyo Content-type: application/json; charset=utf-8en el encabezado del mensaje. Sin este encabezado, recibo un error del servicio. También puedo usar con éxito Content-type: application/jsonsin la ;charset=utf-8porción.

¿Qué hace exactamente charset=utf-8? Sé que especifica la codificación de caracteres, pero el servicio funciona bien sin ella. ¿Esta codificación limita los caracteres que pueden estar en el cuerpo del mensaje?

DenaliHardtail
fuente
44
eche un vistazo a hanselman.com/blog/…
Daniel Powell
8
Curiosamente, de acuerdo con el application/jsonRegistro de tipos de medios de IANA , no parece haber un charsetparámetro compatible en absoluto, aunque a menudo se proporciona en la práctica.
Uux
1
I know it specifies the character encoding but the service works fine without it."trabajar" no siempre significa "el código / configuración existente es la forma más correcta de cubrir todos los casos de esquina para hacer una cosa". Depende de todas las convenciones y suposiciones que pueden no funcionar en otras circunstancias. Para mí personalmente, siempre trato de ser lo más explícito posible.
WesternGun
3
Enviar un parámetro "charset" es incorrecto y no tiene sentido. Ver RFC 8259, Sección 11, última oración.
Julian Reschke

Respuestas:

283

El encabezado solo indica en qué está codificado el contenido. No es necesariamente posible deducir el tipo de contenido del contenido en sí mismo, es decir, no necesariamente puede mirar el contenido y saber qué hacer con él. Para eso están los encabezados HTTP, le dicen al destinatario con qué tipo de contenido están tratando (supuestamente).

Content-type: application/json; charset=utf-8designa el contenido para que esté en formato JSON, codificado en la codificación de caracteres UTF-8. Designar la codificación es algo redundante para JSON, ya que la codificación predeterminada (¿solo?) Para JSON es UTF-8. Entonces, en este caso, el servidor receptor aparentemente está contento de saber que está tratando con JSON y supone que la codificación es UTF-8 de forma predeterminada, por eso funciona con o sin el encabezado.

¿Esta codificación limita los caracteres que pueden estar en el cuerpo del mensaje?

No. Puedes enviar lo que quieras en el encabezado y el cuerpo. Pero, si los dos no coinciden, puede obtener resultados incorrectos. Si especifica en el encabezado que el contenido está codificado en UTF-8 pero en realidad está enviando contenido codificado en Latin1, el receptor puede producir datos basura, intentando interpretar los datos codificados en Latin1 como UTF-8. Si, por supuesto, especifica que está enviando datos codificados en Latin1 y realmente lo está haciendo, entonces sí, está limitado a los 256 caracteres que puede codificar en Latin1.

difunto
fuente
44
Por supuesto, en JSON aún podría representar caracteres no latinos 1 usando secuencias de escape como \u20AC.
dan04
31
De acuerdo con el estándar para json, no está permitido usar latin1 para la codificación de los contenidos. El contenido JSON debe codificarse como unicode, ya sea UTF-8, UTF-16 o UTF-32 (endian grande o pequeño).
Daniel Luna
20
No hay ningún parámetro charset en application / json.
Julian Reschke
77
@DanielLuna tiene razón, application/jsontiene que estar en uno de los formatos de transformación ucs. Además, dado que los primeros cuatro bytes de JSON son limitados, siempre se puede saber si es 8, 16 o 32 y su endianidad.
Jason Coco
44
Evento si es redundante, puede incluirlo charset=utf-8por razones de seguridad: github.com/shieldfy/API-Security-Checklist/issues/25
manuc66
143

Para corroborar la afirmación de @ deceze de que la codificación JSON predeterminada es UTF-8 ...

Desde IETF RFC4627 :

El texto JSON DEBE estar codificado en Unicode. La codificación predeterminada es UTF-8.

Dado que los dos primeros caracteres de un texto JSON siempre serán caracteres ASCII [RFC0020], es posible determinar si un flujo de octetos es UTF-8, UTF-16 (BE o LE) o UTF-32 (BE o LE) al observar el patrón de nulos en los primeros cuatro octetos.

      00 00 00 xx  UTF-32BE
      00 xx 00 xx  UTF-16BE
      xx 00 00 00  UTF-32LE
      xx 00 xx 00  UTF-16LE
      xx xx xx xx  UTF-8
Drew Noakes
fuente
12
Siempre ayuda pensar en JSON como formato binario, no como formato de texto.
Sulthan
2
Ahora que RFC4627 ha quedado obsoleto por RFC7159, que establece que el valor raíz puede ser una cadena (en contraste explícito con la especificación anterior), ¿cómo se implementa ahora? La especificación es vaga a este respecto, y solo dice que se permiten tres codificaciones, pero no cómo se supone que las diferenciamos.
Fabio Beltramini
44
@FabioBeltramini Lo anterior aún debería mantenerse, porque una cadena en JSON no contendrá ningún carácter nulo literal (los nulos en JSON tendrían que codificarse con una secuencia de escape numérica, es decir "\u0000").
thomasrutter
3
En realidad, el segundo carácter en UTF-16xx puede no tener un NULL en ese caso, pero aún será posible determinar la codificación de los otros bytes: xx 00 00 00sigue siendo UTF-32LE y xx 00 xx xxsigue siendo UTF-16LE, 00 xx xx xxsigue siendo UTF-16BE.
thomasrutter
20

Tenga en cuenta que IETF RFC4627 ha sido reemplazado por IETF RFC7158 . En la sección [8.1] se retrae el texto citado por @Drew anteriormente diciendo:

Implementations MUST NOT add a byte order mark to the beginning of a JSON text.
Alex
fuente
Sin embargo, la suposición aún se mantiene, ya que cualquier json válido aún comenzará con dos caracteres ascii.
Larsing
Un carácter, porque un solo número es un archivo JSON válido
Nayuki
0

Estoy exactamente de acuerdo con @deceze pero quiero desarrollar esta parte de la pregunta "Recibo un error del servicio" ,

Recibimos este tipo de errores como http 415

Http 415 Error de tipo de medio no compatible

El código de respuesta de error del cliente de tipo de medio HTTP 415 no compatible indica que el servidor se niega a aceptar la solicitud porque el formato de carga está en un formato no compatible.

El problema de formato puede deberse al Tipo de contenido o la Codificación de contenido indicados en la solicitud , o como resultado de la inspección directa de los datos.

En otras palabras, como se ve en https://stackoverflow.com/a/22643964/914284 este ejemplo.

  • Tenemos que establecer el tipo de contenido correcto y tenemos que aceptar el tipo de contenido correcto como se ve. Agregar tipo de contenido: aplicación / json y Aceptar: aplicación / json. De lo contrario, asumirá el valor predeterminado
Hamit YILDIRIM
fuente
0

La implementación de http de Dart procesa los bytes gracias a ese "charset = utf-8", por lo que estoy seguro de que varias implementaciones lo soportan, para evitar el juego de caracteres alternativo "latin-1" al leer los bytes de la respuesta. En mi caso, pierdo totalmente el formato en la cadena del cuerpo de la respuesta, por lo que debo codificar los bytes manualmente en utf8, o agregar ese parámetro "interno" de encabezado en la respuesta API de mi servidor.

roipeker
fuente
0

Estaba usando HttpClient y recuperando el encabezado de respuesta con tipo de contenido application/json, perdí caracteres como idiomas extranjeros o símbolos que usaban unicode ya que HttpClient está predeterminado en ISO-8859-1 . Por lo tanto, sea lo más explícito posible como lo menciona @WesternGun para evitar cualquier posible problema.

No hay forma de manejar que debido al servidor no maneja charset ( method.setRequestHeader("accept-charset", "UTF-8");) de encabezado solicitado para mí y tuve que recuperar datos de respuesta como bytes de dibujo y convertirlos en String usando UTF-8. Por lo tanto, se recomienda ser explícito y evitar asumir el valor predeterminado.

Tri Nguyen
fuente