Nagłówek HTTP Content-Type i JSON

144

Zawsze starałem się unikać używania większości właściwości protokołu HTTP ze względu na strach przed nieznanym.

Jednak powiedziałem sobie, że dziś zmierzę się ze strachem i zacznę celowo używać nagłówków. Próbuję przesłać jsondane do przeglądarki i od razu z niej korzystać. Na przykład, jeśli mam funkcję obsługi Ajax w stanie gotowości 4, który wygląda tak:

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

I ustawiłem nagłówek typu zawartości w moim kodzie PHP:

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

Dlaczego nie mogę uzyskać bezpośredniego dostępu do właściwości z funkcji obsługi, gdy przeglądarka jest wyraźnie poinformowana, że ​​przychodzące dane są application/json?

php_nub_qq
źródło
Jeśli dobrze rozumiem, chcesz użyć textjako zmiennej javascript w module obsługi, a nie odpowiadać? To byłaby bardzo dziwna funkcjonalność. Json_encode tworzy również 1 obiekt z tablicy PHP. Więc kiedy dostaniesz to do javascript, musi być przypisane do zmiennej.
Flashin
4
Nagłówek contentType zawiera tylko informacje. Przeglądarka użyje tego, jeśli to możliwe, ale w tym przypadku przeglądarki po prostu to zignorują, ponieważ zwykle nie wiedzą, jaki jest zamiar. Twoja aplikacja Javascript może to wykorzystać. Zakładasz, że zostanie przedstawiony JSON, więc możesz go zdekodować za pomocą JSON.parse(). Możesz wykonać inną akcję lub wymusić błąd, jeśli pojawi się nieprawidłowy typ contentType.
1
Przeglądarka nie analizuje automatycznie tekstu JSON, więc response.textnadal jest to ciąg.
nnnnnn
1
Więc chcesz mi powiedzieć, że ustawienie tego nagłówka nie robi różnicy, co tak zawsze? Jaki jest zatem cel jego istnienia?
php_nub_qq
2
@php_nub_qq: Jego celem jest poinformowanie Cię, co zwrócił serwer, aby Twoja aplikacja mogła to odpowiednio obsłużyć. Przeglądarka nie będzie analizować JSON dla Ciebie, Twoja aplikacja musi zrobić. Ten nagłówek mówi ci, że jest (lub powinien być JSON).
Rocket Hazmat

Odpowiedzi:

136

Content-TypeNagłówek jest po prostu używane jako o swojej aplikacji. Przeglądarka nie dba o to, co to jest. Przeglądarka po prostu zwraca dane z połączenia AJAX. Jeśli chcesz przeanalizować go jako JSON, musisz to zrobić samodzielnie.

Nagłówek jest tam, więc Twoja aplikacja może wykryć, jakie dane zostały zwrócone i jak powinna je obsłużyć. Musisz spojrzeć na nagłówek, a jeśli to application/jsonnastępnie przeanalizować go jako JSON.

Tak właśnie działa jQuery. Jeśli nie powiesz mu, co ma zrobić z wynikiem, używa Content-Typeznaku do wykrycia, co z nim zrobić.

Rocket Hazmat
źródło
12
To nie do końca prawda. Jeśli nie użyjesz header('Content-Type: application/json');i nie wymusisz pobierania do Content-Disposition: attachment; filename=myfile.jsontego czasu, otrzymasz plik myfile.json.html. Używając tego nagłówka json, otrzymasz myfile.json.
Remi Grumeau
4
@RemiGrumeau Co to jest „nie do końca prawda”? Pobieranie plików za pomocą przeglądarki to coś zupełnie innego. Przeglądarka prawdopodobnie domyślnie oczekuje HTML, więc zakłada, że ​​wszystko, co otrzymuje, jest HTMLem, chyba że określono inaczej. Podczas pobierania dołącza .htmldo pliku, ponieważ tak jest domyślnie.
bzeaman
2
Nie znam pełnego kontekstu problemu - ALE przeglądarki (i javascript) czasami przejmują się typem treści. Ten nagłówek może wpływać na heurystykę używaną przez przeglądarkę do wyświetlania treści, a wysyłanie XML i JSON z tekstem / html typu treści może często powodować subtelne błędy w bazowych żądaniach XHR (lub warstwach twojego frameworka na wierzchu)
Alan Storm
7

Content-Type: application/jsonto tylko nagłówek treści. Nagłówek treści to po prostu informacja o rodzaju zwracanych danych, np. :: JSON, obraz (png, jpg, itd ..), html.

Pamiętaj, że JSON w JavaScript to tablica lub obiekt. Jeśli chcesz zobaczyć wszystkie dane, użyj console.log zamiast alert:

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

Jeśli chcesz ostrzec oryginalną zawartość JSON jako ciąg, dodaj pojedyncze cudzysłowy ('):

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

Nie używaj cudzysłowów. To zmyli JavaScript, ponieważ JSON używa podwójnych cudzysłowów na każdej wartości i kluczu:

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>
Wśród Amrul
źródło
Nigdy to zrobić, będzie przerwa na dowolny ciąg przy użyciu apostrofów (i to często w wielu językach) echo "'" . json_encode(array('text' => 'it\'s wrong')) . "'"; będzie produkować ten uszkodzony wyjście: '{"text":"it's wrong"}'. Użyj tego zamiast: json_encode(json_encode(array('text' => 'it\'s good'))). Wynik zostanie "{\"text\":\"it's wrong\"}"
usunięty
1

Poniższy kod pomaga mi zwrócić obiekt JSON dla JavaScript w interfejsie użytkownika

Mój kod szablonu

template_file.json

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

Kod wspierany przez Pythona

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")    

Plik url.py

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

Kod jQuery dla interfejsu

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