183

I have always been trying to avoid using most of the HTTP protocol's properties for the sake of fear of the unknown.

However, I said to myself that I'm going to face fear today and start using headers purposefully. I have been trying to send json data to the browser and use it right away. For example, if I have an Ajax handler function on ready state 4 which looks like so:

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

And I have set the content-type header in my PHP code:

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

Why can't I directly access the property from the handler function, when the browser is clearly told that the incoming data is application/json?

Christopher Peisert
  • 21,862
  • 3
  • 86
  • 117
php_nub_qq
  • 15,199
  • 21
  • 74
  • 144
  • If i understand correctly, you would like to use `text` as a javascript variable in the handler and not response? That would be very weird functionality. The json_encode also creates 1 object out of your PHP array. So when you get this into javascript it needs to be assigned to a variable. – Flashin Dec 16 '13 at 20:33
  • 4
    The contentType header is information only. The browser will use that if it can, but in this case the browsers simply ignore it because they don't usually know what the intent is. Your Javascript application _can_ make use of it. You're assuming that JSON will be presented, so you can decode it with `JSON.parse()`. You could take some different action, or force an error if the wrong contentType appears. –  Dec 16 '13 at 20:34
  • 1
    The browser doesn't automatically parse the JSON text for you, so `response.text` is still a string. – nnnnnn Dec 16 '13 at 20:34
  • 1
    So you mean to tell me that setting that header makes no difference what so ever? What is the purpose of it's existence then? – php_nub_qq Dec 16 '13 at 20:35
  • 2
    @php_nub_qq: It's purpose is to tell you what the server returned so your application can handle it accordingly. The *browser* won't parse the JSON for you, your app needs to do that. This header is telling you that it is (or should be JSON). – gen_Eric Dec 16 '13 at 20:38
  • @RocketHazmat ok so maybe you should put that as an answer or I should delete this question I guess `;/` – php_nub_qq Dec 16 '13 at 20:42
  • I don't know what these people are talking about... It DOES make a difference! At least in Firebase Cloud Functions and in c#... See this, for example: https://stackoverflow.com/a/73599552/14335655 – Karolina Hagegård Nov 27 '22 at 07:37

5 Answers5

162

The Content-Type header is just used as info for your application. The browser doesn't care what it is. The browser just returns you the data from the AJAX call. If you want to parse it as JSON, you need to do that on your own.

The header is there so your app can detect what data was returned and how it should handle it. You need to look at the header, and if it's application/json then parse it as JSON.

This is actually how jQuery works. If you don't tell it what to do with the result, it uses the Content-Type to detect what to do with it.

Luke Stevenson
  • 10,357
  • 2
  • 26
  • 41
gen_Eric
  • 223,194
  • 41
  • 299
  • 337
  • 19
    That's not totally true. If you don't use `header('Content-Type: application/json');` and force download by `Content-Disposition: attachment; filename=myfile.json` then you'll end up with a `myfile.json.html`. Using this json header, you'll get `myfile.json`. – Remi Grumeau Mar 04 '16 at 09:52
  • 8
    @RemiGrumeau What is 'not totally true'? Downloading files with browser is something completely different. The browser will probably default to expect HTML, so it assumes anything it receives is HTML unless otherwise specified. When downloading, it appends `.html` to the file, because that's what it defaults to. – bzeaman Apr 22 '17 at 14:01
  • 3
    I don't know the full context of the problem here -- BUT, browsers (and javascript) do care about Content-Type sometimes. This header can impact the heuristics a browser uses to display content, and sending XML and JSON with a content-type of text/html can often create subtle bugs in the underlying XHR requests (or your framework's layers on top of those) – Alana Storm Sep 28 '17 at 21:23
  • 1
    When I have pages generating JSON data, I place this header. Because under Mozilla Firefox for example without the header the data is not formatted while with the header it is formatted and very readable. – Juan May 28 '21 at 08:06
  • Continuing this tangent, it also has consequences for CORS. Post requests with content-type of json will be preflighted. Others do not (for legacy compatibility from before CORS). – dQw4w9WyXcQ Nov 13 '22 at 00:50
  • This answer is wrong! Un-accept it! It's NOT "just information"... as if it didn't have any function. In my applications, this header DOES automatically parse the argument into a JSON object! If I try to JSON parse it again, I get an error! See this, for example: https://stackoverflow.com/a/73599552/14335655 – Karolina Hagegård Nov 27 '22 at 07:42
13

This is old but for me PHP8 it works if the charset is set example.

header('Content-Type: application/json; charset=utf-8');
echo json_encode(array('text' => 'eggs'));
Elikill58
  • 4,050
  • 24
  • 23
  • 45
Ncoder
  • 131
  • 1
  • 4
12

Content-Type: application/json is just the content header. The content header is just information about the type of returned data, ex::JSON,image(png,jpg,etc..),html.

Keep in mind, that JSON in JavaScript is an array or object. If you want to see all the data, use console.log instead of alert:

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

If you want to alert the original JSON content as a string, then add single quotation marks ('):

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

Do not use double quotes. It will confuse JavaScript, because JSON uses double quotes on each value and key:

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>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Among Amrul
  • 157
  • 1
  • 4
  • 1
    Never do this, it will break on any string using single quotes (and it's frequent in many languages) : `echo "'" . json_encode(array('text' => 'it\'s wrong')) . "'";` will produce this broken output : `'{"text":"it's wrong"}'`. Use this instead : `json_encode(json_encode(array('text' => 'it\'s good')))`. Outcome will be escaped correctly : `"{\"text\":\"it's wrong\"}" ` – PofMagicfingers Mar 11 '19 at 15:12
  • What do you mean "just the content header"?!... The content header does parse the content, just as the qn-maker intended! Or maybe 8 years ago, when the qn was asked, it didn't...? Well, now it does. See this: https://stackoverflow.com/a/73599552/14335655 – Karolina Hagegård Nov 27 '22 at 07:46
1

The below code helps me to return a JSON object for JavaScript on the front end

My template code

template_file.json

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

Python backed code

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

File url.py

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

jQuery code for the front end

  $.ajax({
        url:'{% url 'download_json-url' %}'        
    }).done(function(data){
        console.log('json ', data);
        console.log('Name', data.name);
        alert('hello ' + data.name);
    });
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alex Vera
  • 29
  • 3
1

Recently ran into a problem with this and a Chrome extension that was corrupting a JSON stream when the response header labeled the content-type as 'text/html'.

Apparently extensions can and will use the response header to alter the content before the browser processes it.

Changing the content-type fixed the issue.

Tms91
  • 3,456
  • 6
  • 40
  • 74