Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

$http is parsing a request to JSON ignoring the content-type #15897

Closed
1 of 3 tasks
jrivera294 opened this issue Apr 6, 2017 · 10 comments
Closed
1 of 3 tasks

$http is parsing a request to JSON ignoring the content-type #15897

jrivera294 opened this issue Apr 6, 2017 · 10 comments

Comments

@jrivera294
Copy link

jrivera294 commented Apr 6, 2017

I'm submitting a ...

  • bug report
  • feature request
  • other (Please do not submit support requests here (see above))

Current behavior:
The transformResponse is being executed based on a text/plain content, instead of the content-type headers, causing errors sometimes.

Expected / new behavior:
The transformResponse has to be called based on the content-type headers.

Minimal reproduction of the problem with instructions:
$http.get is trying parse to json a text/plain response (the content-type header from the server is "text/plain") when the text starts with "[" and ends with "]" characters.

Looking the documentation for baddata it says that it parses the body when the content-type header is application/json, and "the response looks like a valid JSON-stringified object or array".

And when I change the default transformResponse function to:
$http.get('/', { transformResponse: [function (data) { return data; }] })
To do nothing when it's called, the request works.

The $http request ignores the content-type response header and try to parse my response based in the body of the response?

Angular version: 1.6.2

Browser: all

Anything else:
I'm not sure how it detects that the body "looks like" a json to parse it automatically. But if the content-type of the response is "text/plain" it doesn't have to parse it, even if the body is a json object (not my case).

@Narretz
Copy link
Contributor

Narretz commented Apr 7, 2017

Originally, AngularJS ignored the content type header completely and always tried to parse JSON: 7b6c1d0 This was changed to additionally always parse when the content-type header is set, and after that, only the json-likeness detection was updated.

Changing this would possibly break a lot of apps that simply don't set their content-type headers on the server correctly.

If you know that your response will always return text, you can detect this and skip the default transform, e.g. like this http://plnkr.co/edit/DgNEA1s62brfhVgsv6OL Or, if your API always returns text, remove the default http transform.

Note that the error you linked to is valid only from 1.6.4 onwards - before that you get a generic JSOn parse error.

But you are right that the error description is not correct about the workaround, because setting the header doesn't fix it.

@Narretz Narretz added this to the Backlog milestone Apr 7, 2017
@Narretz
Copy link
Contributor

Narretz commented Apr 7, 2017

We could also employ some advanced heuristics to detect that this is not json, but this basically means we would have to parse the JSON. Pinging @gkalpak since he last worked on this code.

Narretz added a commit to Narretz/angular.js that referenced this issue Apr 7, 2017
- baddata error described incorrect http behavior, and workarounds
- httpProvider defaults were missing transformResponse / transformRequest
- http was not clear about JSON detection strategy

Closes angular#15897
@jrivera294
Copy link
Author

Question:

The responseType option shouldn't define the expected content-type?

And if that option doesn't do it, we can't add an option to set the expected content-type and don't try to parse to json?

Because even if we improve it with advanced heuristics, if we send a json object as text, or something that still appears to be a json we will have the same problem.

@Narretz
Copy link
Contributor

Narretz commented Apr 7, 2017

Yes, this is the current status quo. Text that looks like json according to our detection will be parsed as such. We could add an option, but I don't know many devs would benefit from this, especially since there are workarounds.

@gkalpak
Copy link
Member

gkalpak commented Apr 11, 2017

At this point, I agree it is probably not worth addressing other than documenting the current behavior and work-around (as it could be a significant breaking change) 👍

Narretz added a commit that referenced this issue Apr 12, 2017
- baddata error described incorrect http behavior, and workarounds
- httpProvider defaults were missing transformResponse / transformRequest
- http was not clear about JSON detection strategy

Closes #15897 
Closes #15906
Narretz added a commit that referenced this issue Apr 21, 2017
- baddata error described incorrect http behavior, and workarounds
- httpProvider defaults were missing transformResponse / transformRequest
- http was not clear about JSON detection strategy

Closes #15897 
Closes #15906
@alexellis
Copy link

alexellis commented Feb 22, 2018

Hi folks,

I found this thread through Google and was not expecting the conclusion:

I agree it is probably not worth addressing

I think I'm seeing the same issue as described above but don't know how to get $http to stop parsing as JSON.

The HTTP call returns text/plain but the value looks similar to JSON (it is not JSON) and this breaks the page. I'm setting the request/response types to text but the success part of the promise never executes.. just the error part with a parsing error.

Please could you point me at the docs or workaround that I can use to prevent angular / $http from force-parsing text as if it were JSON? Related openfaas/faas#528

The plain-text value is: '[\n "foo" => "foo"\n]' and the content-type from the server is text/plain.

The code driving the page is here: https://github.com/openfaas/faas/blob/master/gateway/assets/script/bootstrap.js#L93

screen shot 2018-02-22 at 9 17 13 am

Thanks in advance for your help.

@petebacondarwin
Copy link
Contributor

@alexellis - The workaround depends upon your situation. See #15897 (comment)

The heavy-handed approach (which especially works if you never get JSON from $http requests) is to remove the default transform from the $http service.

Otherwise you could remove the default transform on a request by request basis.

Or finally you could replace the default transform with a more complex one that is able to work out whether your request expected JSON or not.

@alexellis
Copy link

Thanks for a quick response @petebacondarwin. The UI for OpenFaaS can invoke functions via a web form - it looks similar to Postman. So you will see a request body entered and can indicate its format and after invoking will see the response in the bottom part of the screen. I believe we should largely be able to detect the content through the Content-Type sent back from the server.

I looked at the plunker example but I don't see how the function transformData relates to the $http module in that example or how it is specifically preventing the parsing as JSON? Can you talk me through it?

Example:

screen shot 2018-02-22 at 9 41 10 am

@petebacondarwin
Copy link
Contributor

petebacondarwin commented Feb 22, 2018

Yes, that Plunker is not very helpful :-/

Here is the relevant section in the docs: https://docs.angularjs.org/api/ng/service/$http#transforming-requests-and-responses

The general idea would be to override the transform in your request:

$http({
  url: '...',
  method: 'GET',
  transformResponse: myTranformFn
});

where myTransformFn will look something like:

function myTransformFn(data, headersGetter, status) {
  if (isJsonType(headersGetter()['Content-Type']) {
    return JSON.parse(data);
  } else {
    return data;
  }
}

@Narretz
Copy link
Contributor

Narretz commented Feb 22, 2018

I believe we changed this behavior here: 7f2acca#diff-748e0a1e1a7db3458d5f95d59d7e16c9 so that http will only throw if the content type is set to json, but can't be parsed. This is available in 1.6.6. Open Faas uses AngularJS 1.5.5. So this could be fixed by updating AngularJS

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants