Encabezado de tipo de contenido HTTP y JSON

144

Siempre he tratado de evitar usar la mayoría de las propiedades del protocolo HTTP por miedo a lo desconocido.

Sin embargo, me dije a mí mismo que hoy voy a enfrentar el miedo y comenzar a usar encabezados a propósito. He estado tratando de enviar jsondatos al navegador y usarlos de inmediato. Por ejemplo, si tengo una función de controlador Ajax en estado listo 4 que se ve así:

function ajaxHandler(response){
    alert(response.text);
}

Y he configurado el encabezado de tipo de contenido en mi código PHP:

header('Content-Type: application/json');
echo json_encode(array('text' => 'omrele'));

¿Por qué no puedo acceder directamente a la propiedad desde la función de controlador, cuando se le dice claramente al navegador que los datos entrantes son application/json?

php_nub_qq
fuente
Si lo entiendo correctamente, ¿le gustaría usarlo textcomo una variable de JavaScript en el controlador y no responder? Esa sería una funcionalidad muy extraña. Json_encode también crea 1 objeto a partir de su matriz PHP. Entonces, cuando obtienes esto en javascript, debe asignarse a una variable.
Flashin
44
El encabezado contentType es solo información. El navegador lo usará si puede, pero en este caso los navegadores simplemente lo ignoran porque generalmente no saben cuál es la intención. Su aplicación Javascript puede usarla. Asume que se presentará JSON, por lo que puede decodificarlo JSON.parse(). Podría tomar alguna acción diferente o forzar un error si aparece el tipo de contenido incorrecto.
1
El navegador no analiza automáticamente el texto JSON por usted, por response.textlo que sigue siendo una cadena.
nnnnnn
1
Entonces, ¿quieres decirme que establecer ese encabezado no hace ninguna diferencia? ¿Cuál es el propósito de su existencia entonces?
php_nub_qq
2
@php_nub_qq: Su propósito es decirle qué devolvió el servidor para que su aplicación pueda manejarlo en consecuencia. El navegador no analizará el JSON por usted, su aplicación debe hacerlo. Este encabezado te dice que es (o debería ser JSON).
Rocket Hazmat

Respuestas:

136

El Content-Typeencabezado solo se usa como información para su aplicación. Al navegador no le importa lo que es. El navegador solo le devuelve los datos de la llamada AJAX. Si desea analizarlo como JSON, debe hacerlo por su cuenta.

El encabezado está allí para que su aplicación pueda detectar qué datos se devolvieron y cómo debe manejarlos. Debe mirar el encabezado y, si es así, application/jsonanalizarlo como JSON.

Así es como funciona jQuery. Si no le dice qué hacer con el resultado, lo utiliza Content-Typepara detectar qué hacer con él.

Cohete Hazmat
fuente
12
Eso no es totalmente cierto. Si no usa header('Content-Type: application/json');y fuerza la descarga para Content-Disposition: attachment; filename=myfile.jsonentonces, terminará con un myfile.json.html. Usando este encabezado json, obtendrás myfile.json.
Remi Grumeau
44
@RemiGrumeau ¿Qué es "no totalmente cierto"? Descargar archivos con el navegador es algo completamente diferente. El navegador probablemente esperará HTML de forma predeterminada, por lo que supone que todo lo que recibe es HTML a menos que se especifique lo contrario. Al descargar, se agrega .htmlal archivo, porque eso es lo que está predeterminado.
bzeaman
2
No sé el contexto completo del problema aquí, PERO, los navegadores (y javascript) a veces se preocupan por Content-Type. Este encabezado puede afectar la heurística que utiliza un navegador para mostrar contenido, y enviar XML y JSON con un tipo de contenido de texto / html a menudo puede crear errores sutiles en las solicitudes XHR subyacentes (o las capas de su marco encima de ellas)
Alan Storm
7

Content-Type: application/jsones solo el encabezado del contenido. El encabezado del contenido es solo información sobre el tipo de datos devueltos, por ejemplo, JSON, imagen (png, jpg, etc.), html.

Tenga en cuenta que JSON en JavaScript es una matriz u objeto. Si desea ver todos los datos, use console.log en lugar de alertar:

alert(response.text); // Will alert "[object Object]" string
console.log(response.text); // Will log all data objects

Si desea alertar al contenido JSON original como una cadena, agregue comillas simples ('):

echo "'" . json_encode(array('text' => 'omrele')) . "'";
// alert(response.text) will alert {"text":"omrele"}

No use comillas dobles. Confundirá JavaScript, porque JSON usa comillas dobles en cada valor y clave:

echo '<script>var returndata=';
echo '"' . json_encode(array('text' => 'omrele')) . '"';
echo ';</script>';

// It will return the wrong JavaScript code:
<script>var returndata="{"text":"omrele"}";</script>
Entre Amrul
fuente
Nunca haga esto, se romperá en cualquier cadena utilizando comillas simples (y es frecuente en muchos idiomas): echo "'" . json_encode(array('text' => 'it\'s wrong')) . "'"; producirá esta salida roto: '{"text":"it's wrong"}'. Use este lugar: json_encode(json_encode(array('text' => 'it\'s good'))). El resultado se "{\"text\":\"it's wrong\"}"
escapará
1

El siguiente código me ayuda a devolver un objeto JSON para JavaScript en el front-end

Mi código de plantilla

template_file.json

{
    "name": "{{name}}"
}

Código respaldado por Python

def download_json(request):
    print("Downloading JSON")
    # Response render a template as JSON object
    return HttpResponse(render_to_response("template_file.json",dict(name="Alex Vera")),content_type="application/json")    

Archivo url.py

url(r'^download_as_json/$', views.download_json, name='download_json-url')

Código jQuery para el front end

  $.ajax({
        url:'{% url 'download_json-url' %}'        
    }).done(function(data){
        console.log('json ', data);
        console.log('Name', data.name);
        alert('hello ' + data.name);
    });
Alex Vera
fuente