In my Ember project, I use the following code to get a JSON response from my back-end:
Ember.$.getJSON(
mybackendurl.foo/mybarroute,
function (data) {
console.log(data);
});
And there, I get the following error message: SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data.
My back-end is written in PHP using Symfony, and VoryxRESTGeneratorBundle to send JSON. When I visit http://mybackendurl.foo/mybarroute on my browser, I get a nice JSON response:
{
"links":
[
{
"id": 28,
[...]
}
]
}
It looks like the answer is not correctly detected when using Ember. I'm unsure if the problem comes from back or front-end. How should I fix this?
Additional information:
1) This code in Ember generate a OPTION request, with an empty 200 response:
Ember.$.ajax({
url: http://mybackendurl.foo/mybarroute,
type: 'GET',
contentType: 'application/json'
});
2) I had no more results using chrome
3) Request and response headers
Update
Based on updated Request Response headers, I would guess you are running into Cross-domain problem. Your server runs on PORT 8000, and front-end runs on Port 4200
Either considering going to a JSONP solution or Enable CORS in your server.
Because browser does not support cross domain, you get an error, which ember thinks is a bad JSON.
Here's how you can return JSONP from symfony:
Returning JSONP from Symfony2 controller using AJAX call
Once your server supports a callback parameter in URL, and responds with a callback({your json})
Here's how to use jsonp from Ember:
How do I use the JSONP datatype with Ember Data?
I don't think you've configured CORS on your server, your browser can't receive data from something with a different origin unless CORS is configured correctly.
If you do curl -IX OPTIONS http://whateverisyoururl it should at a minimum send something like this back in the headers:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, OPTIONS
This isn't an ember.js issue, it's a general cross origin request issue.
It turned out to be a configuration problem in nelmio_cors. The thing that got me speding hours is the caching: max_age was set to 3600, so I should have waited 1 hour to see the effect applied.
Setting it to 0 solved my problem.
nelmio_cors:
defaults:
allow_credentials: true
allow_origin: ['*']
allow_headers: ['Origin', 'X-Requested-With', 'Content-Type', 'Accept']
allow_methods: ['GET', 'POST', 'PUT', 'OPTIONS', 'PATCH', 'DELETE']
expose_headers: []
max_age: 0
hosts: []
origin_regex: false
paths:
'^/api/':
allow_origin: ['*']
allow_headers: ['Origin', 'X-Requested-With', 'Content-Type', 'Accept']
allow_methods: ['GET', 'POST', 'PUT', 'OPTIONS', 'PATCH', 'DELETE']
max_age: 0
Try this..
Ember.$.ajax({
url: http://mybackendurl.foo/mybarroute,
type: 'GET',
contentType: 'application/json',
dataType: 'json',
success: function(result){
console.log(result);
}});
and also does your url dont have extensions? i mean something like, mybarroute.php,.json,.js, or .html?
Related
I am trying to call an API that accepts OPTIONS method on server, it runs on postman and returns json object but following code is not working on js
I have read that OPTIONS call is a preflight call for CORS calls, so this API is https and on another server. But even then there is no response and it returns 405 method not found
$.ajax({
url: url,
dataType: "jsonp",
method :"OPTIONS",
crossDomain: true,
contentType: 'application/json',
headers: {
"Content-type": "application/json",
"Cache-Control": "no-cache",
"Accept": "application/json,long_format",
"Access-Control-Allow-Origin": "*"
},
success: function (data) {
console.log("success" + data);
},
error: function (data) {
console.log("fail" + data);
}
}).fail(function(data) {
console.log("failed" + data);
});
Extra info :
The API is cross domain and on ssl so to cover cross domain request I had to user dataType: "jsonp"
UPDATED :
This is impossible scenario so I have to get update on server end...
Explanation:
There is some problem with
OPTIONS method that is behind cross domain as well
a/c to some research i have done on internet, CORS request can be accessed with :
dataType: "jsonp",
but with -> dataType: "jsonp"
you can only call GET methods
so we are stuck here that allows that either we call cross domain https request or we can call OPTIONS method,
usually OPTIONS method is a preflight method done automatically by browser
NOW please stop down voting my question
dataType: "jsonp",
Take this out. JSONP requests are always GET requests. This is your main problem.
crossDomain: true,
Take this out. It does nothing unless you are making a same origin request that gets redirected to be a cross origin request.
contentType: 'application/json',
Take this out. You are making an OPTIONS request. There is no request body to describe the content-type of.
"Content-type": "application/json",
Take this out. For the same reason.
"Access-Control-Allow-Origin": "*"
Take this out. It is a response header and has no place on the request.
Here when I trying to print response in browser console. It shows this error
Cross-Origin Read Blocking (CORB) blocked cross-origin response https://script.google.com/macros/s/AKfycbwmqG55tt2d2FcT_WQ3WjCSKmtyFpkOcdprSITn45-4UgVJnzp9/exec?url=http://35.230.52.177:8095/OneSoftTracking/rest/tracking/consignment/AE101632?hostname=aastha-enterprises.com&callback=jQuery1124008693115102408444_1561964934754&_=1561964934755 with MIME type text/html. See https://www.chromestatus.com/feature/5629709824032768 for more details.`
While when I get data in Postman like:
This warning or error showing :
This is my code :
var settings = {
async: true,
crossDomain: true,
crossOrigin: true,
url: "http://35.230.52.177:8095/OneSoftTracking/rest/tracking/consignment/AE101632?hostname=aastha-enterprises.com",
method: "GET",
"headers": {
"Content-Type":"application/json",
"Access-Control-Allow-Origin":"*",
'Access-Control-Allow-Methods':'GET',
'Access-Control-Allow-Credentials' : true,
"Accept": "*/*",
"Cache-Control": "no-cache",
"Postman-Token": "bea2b074-eefc-473e-84d7-b680a07ed7df,dafa4f5c-94af-4efe-967f-75a9fe185a1e",
},
success: function(data) {
console.log("+++++SuCCESS");
console.log(data);
},
error: function(error){
console.log("NOT SUCCEED");
}
}
$.ajax(settings).done(function (response) {
console.log(response);
});
You haven't shown us your real code.
The error message clearly shows a callback in the query string which isn't in your URL and shouldn't be added because you haven't said dataType: 'jsonp' in the jQuery ajax configuration.
Your real code is configured to use JSONP.
A JSONP response is a JavaScript program (specifically one which calls a single function with a set of arguments). The response you are getting from the server is an HTML document (the content type is text/html and not application/javascript).
The CORB error is the browser telling you that the response is HTML and not JSONP so it is refusing to try to execute it.
The Postman screenshot shows that you are expecting a JSON (still not JSONP) response (but you aren't getting that either).
You need to either:
Change the server to respond with JSONP
Change the request to ask for the correct data (and possibly also change the server to grant you permission to read it using CORS)
Further reading:
What is JSONP, and why was it created?
XMLHttpRequest cannot load XXX No 'Access-Control-Allow-Origin' header
Notes about your code:
async: true,
This is the default, get rid of it
crossDomain: true,
This is the default for cross origin requests, get rid of it.
crossOrigin: true,
This is the default for cross origin requests, get rid of it.
method: "GET",
This is the default, get rid of it
"Content-Type": "application/json",
You are making a GET request. There is no request body to describe the type of. This is nonsense. Get rid of it.
"Access-Control-Allow-Origin": "*",
'Access-Control-Allow-Methods': 'GET',
'Access-Control-Allow-Credentials': true,
These are response headers, not request headers. Putting them on the request is nonsense. Get rid of them.
"Accept": "*/*",
The default is almost certainly going to be fine. You probably don't need to override it.
"Cache-Control": "no-cache",
The main config option "cache" is probably a better choice than explicitly setting the header.
"Postman-Token": "bea2b074-eefc-473e-84d7-b680a07ed7df,dafa4f5c-94af-4efe-967f-75a9fe185a1e",
The odds of your server caring about this are remote. You can probably get rid of this.
Right now, I'm trying to do a post request:
https://aleapisoap.azure-api.net/httpbin/listSearchFields
And I need a body which is this:
{
"listSearchFields": {
"email": "sample"
}
}
I tried this in postman and works but with this code in JavaScript doesn't work.
$.ajax({
url: 'https://aleapisoap.azure-api.net/httpbin/listSearchFields',
headers: {
'Content-Type':'application/json',
'Cache-Control':'no-cache',
'Ocp-Apim-Trace':'true',
'Ocp-Apim-Subscription-Key':'19f2a7fd474840bfb5fc729cd97b7335'
},
type: 'POST',
dataType: 'jsonp',
data: '{"listSearchFields":{"email":"sample"}}',
success: function(data){
console.log('succes: '+data);
}
});
This is the error:
net::ERR_ABORTED 404 (Resource Not Found)
The headers in your $.ajax() call look correct to me. I think the "listSearchFields" endpoint doesn't exist at https://aleapisoap.azure-api.net/httpbin/ like you're expecting. Check your spelling first - if you're spelling "listSearchFields" correctly, you'll have to dive deeper to figure out why it's not being found.
dataType: 'jsonp',
JSONP requests are incompatible with setting custom request headers or making POST requests. They work by injecting a <script> element with a src attribute (which makes a GET request).
If you need to make a POST request, don't use that dataType. You probably want 'json'.
JSONP is a hack that was used to work around the Same Origin Policy before CORS was available. You might have to take other steps to ensure the endpoint is available to your origin.
I'm using Angular's http function to access my remote API service.
At the moment, my API service is offline, and if users try to access it, it still throws a 200 status which is 'ok' with Angular. Therefore, my success callback is always called instead of my error callback. Weird thing is, if I use a REST client, such as POSTman, it has a status of 404?
Here is my function to call my API (using jQuerys $.param() function for URL friendly post parameters):
$http({
method: 'POST',
url: "http://mydomain/api/login",
data: $.param({
username: "test",
password: "test"
}),
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).then(successCallback(response), errorCallback(response));
Here is the response it gives when logged:
{data: "
↵<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN…r at [my ip address] Port 80</address>↵</body></html>↵", status: 200, config: Object, statusText: "OK"}
The response when the API is working is usually something along the lines of:
{
data: {
id: 123
},
status: 200,
config: object,
statusText: 'ok'
}
Sure, theres a few dodgy things that I could do here such as writing a http interceptor to check if data is of type object, yet that's not really the answer I'm looking for here since some of my API calls just return a boolean value.
I also tried changing the 'Content-Type' to 'application/json', yet no luck.
I need my error callback to be used if my API is down. Is there an elegant solution to this?
It all sounds a bit hacky, the most appropriate approach I can think of is to send a 404 / 500 from the API endpoints until it comes online.
Otherwise, try to set an Accept header:
{
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
}
Currently I am using angularJS and CoffeeScript to try to send a post request, and my sample code is:
login: (user, callback)=>
baseUrl = 'http://localhost:3000/api/v1/sessions'
#$http({
method: 'POST',
url: baseUrl,
data: user
}).success (result)->
callback(result)
But when I call it, it just send 'OPTIONS' request instead of POST request.
And the request detail is:
If I add header to this method,
login: (user, callback)=>
baseUrl = 'http://localhost:3000/api/v1/sessions'
#$http({
method: 'POST',
url: baseUrl,
data: user,
headers:
'Content-Type': 'application/json'
}).success (result)->
callback(result)
It still doesn't works, but if I change headers to 'Content-Type': 'application/x-www-form-urlencoded', then it can send post requests.
But the request Content-type is not not I want.
I also try to modify the request data to JSON by: data: JSON.stringify(user), but still not working.
UPDATES
Guys, I did another spike on this issue. Which is I am jquery to send the request and it works fine, but I found an wired thing that is they have different request data.
Jquery
$.ajax({
type: "POST",
url: "http://localhost:3000/api/v1/sessions",
data: {
"user":{
"email":"wahxxx#gmail.com",
"password":"123456"
}
},
success: function(){
}
Screenshot for Jquery
Angular
login: (user, callback)=>
baseUrl = 'http://localhost:3000/api/v1/sessions'
#$http({
method: 'POST',
url: baseUrl,
data: {
"user":{
"email":"wahxxx#gmail.com",
"password":"123456"
}
},
headers:
'Content-Type': 'application/x-www-form-urlencoded'
}).success (result)->
callback(result)
Now it can send request,but I just got 401 when trying to do request.
Screenshot for Angular
So I think the issue may due to the format of the angular request data.
You are hitting CORS restrictions and same origin policy.
Easiest solution is to deploy web frontend and the api together as one app. If ports are different even on the same machine then one needs to deal with same origin policy.
Options is a preflight query. Make your backend accept it and it should be fine.
More reading:
http://www.html5rocks.com/en/tutorials/cors/