Javascript: Cross-domain JSON request issues - php

I am trying to request JSON from Google Places API, but I am still getting the cross-domain request error after firstly including:
<?php
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Methods: POST, GET");
header("Access-Control-Allow-Headers: x-requested-with");
?>
The JSON request I am using is standard JQuery:
function load() {
var url = 'https://maps.googleapis.com/maps/api/place/details/json?reference=CnRhAAAARMUGgu2CeASdhvnbS40Y5y5wwMIqXKfL-n90TSsPvtkdYinuMQfA2gZTjFGuQ85AMx8HTV7axABS7XQgFKyzudGd7JgAeY0iFAUsG5Up64R5LviFkKMMAc2yhrZ1lTh9GqcYCOhfk2b7k8RPGAaPxBIQDRhqoKjsWjPJhSb_6u2tIxoUsGJsEjYhdRiKIo6eow2CQFw5W58&sensor=true&key=xxxxxxxxxxxxxx';
$.ajax(url, {
async: true,
success: function(data, textStatus, jqXHR) {
dump(data);
}
});
}
I would use a JSONP query instead, but the Google Places API doesn't support JSONP...how can I solve this? With a proxy server? I am not sure how to go about this or what I'm doing wrong.

The URL you are requesting data from has to grant permission with access control headers. It would defeat the object of the same origin policy is a remote origin could grant permission to itself!
If the API you are using doesn't provide a JSON-P API, and doesn't set access control headers itself, then you need to use a proxy. Either one you run yourself, or a third party one that will convert to JSON-P (such as YQL).

Related

React + PHP API throws CORS preflight error

I am trying to call a PHP API running on localhost:8000 from a React app running on localhost:3000. After many tries I am still getting "CORS Preflight Did Not Succeed" error.
Sent from the React app:
Sent from the devtools:
My API has following headers:
if (#$_SERVER['HTTP_ORIGIN']) {
header("Origin: http://localhost:8000");
header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Max-Age: 1000');
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');
}
I call the API with fetch like this (but it somehow sends empty request body):
let inputData:object = {email, password}
fetch("http://localhost:8000/data/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(inputData)
})
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error)
})
The strange thing is that the requests are working normally when sent directly from the browser devtools (2nd screenshot) or API clients like Insomnia:
Problem
Your first screenshot indicates that the response to the preflight request has status code 404. However, a necessary condition for CORS preflight to succeed is an ok status (i.e. a status in the range 2xx). See the relevant section (3.2.3) of the Fetch standard:
A successful HTTP response, i.e., one where the server developer intends to share it, to a CORS request can use any status, as long as it includes the headers stated above with values matching up with the request.
A successful HTTP response to a CORS-preflight request is similar, except it is restricted to an ok status, e.g., 200 or 204.
(my emphasis)
Solution
Make sure your server responds with a 2xx status to preflight requests that are meant to succeed.
Additional remarks
Allowing the Origin header is never necessary, simply because it's set by the user agent. You can drop Origin from the value of the Access-Control-Allow-Headers response header.
Why you're setting an Origin header in the response is unclear... Origin is a request header. You should be able to drop that header("Origin: http://localhost:8000"); line.
Instead of "manually" implementing CORS (which is error-prone), you should consider using a proven CORS middleware.
Your cors origin must be localhost:3000.
header("Origin: http://localhost:3000");
Because your frontend running on 3000.
Where the request comes from should be added as cors definition.
Make sure you are not outputting anything in php before returning the response to the frontend application. A simple echo "test"; or a print_r, vardump etc. can trigger this error.
Also, make sure there are no empty lines before the opening <?php tags since they send a premature response to the frontend that may cause this error.

Cors enabled on php file, but still getting error

I'm building an API, for training purposes. I now have to send a POST request containing information. I'm using React JS and PHP, the problem is that everytime I send a request, the CORS error still shows up on the browser.
My JS file that sends the POST is, I changed the URL, because it's on my personal server:
axios.post('https://myurl/api/book/create.php', {
data: JSON.stringify(values, 0, 2)
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
and on the server side, I have the following
<?php
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
With postman the request goes smoothly, but every single time sending through the browser
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://myurl/api/book/create.php. (Reason: CORS request did not succeed
Please make sure that you allow CORS in backend server. Then, you need send header for axios like following example
axios.defaults.headers.post['Content-Type'] = 'application/json';
axios.defaults.withCredentials = true;
axios.defaults.crossDomain = true;
(Or setting it in third paramenter after data)
You have to use either localhost or 127.0.0.1 for all the requests. In general in your code you should make calls to the server by just appending the URI to the current host, without re-adding the host and port in the URI string.
Answer based on: CORS request did not succeed

Using Fetch API instead of Ajax for Allow-Credentials + POST requests

This scenario uses Access-Control-Allow-Credentials alongside the POST method to manage server-side PHP session variables that must remain intact.
For reference, the front-end is a create-react-app project running at http://localhost:3000 and the back-end is PHP running on example.com.
Achieving this with the $.ajax() method is easy and straightforward.
UseAjax(incomingData) {
return new Promise(function(resolve, reject) {
$.ajax({
url: 'http://example.com/api.php',
type: 'post',
data: incomingData,
xhrFields: { withCredentials: true },
success: function(data) {
console.log(data)
}
})
.then((data,status) => {
// Get the result and transform into valid JSON
if ( typeof data === typeof 'str' ) {
try {
data = JSON.parse(data);
} catch(e) {
reject(data,status);
console.log('Exception: ', e);
console.log('API Returned non-JSON result: ', data);
}
}
return data;
}).then((dataObject) => {
console.log('dataObject:');
console.log(dataObject);
resolve(dataObject);
});
});
}
Oddly enough though, when using the fetch() API, it is under the impression that I am not allowing CORS. Of course I have CORS enabled as this request works fine with Ajax and only fails while using the fetch() API.
Here is a look at what I tried while using the fetch() API.
UseFetch(requestData) {
return new Promise(function(resolve, reject) {
console.log('Relay() called with data: ', requestData);
fetch('http://example.com/api.php', {
method: 'POST', // or 'PUT'
body: JSON.stringify(requestData), // data can be `string` or {object}!
headers: new Headers({
'Content-Type': 'application/json'
})
}).then((result) => {
// Get the result
return result.json();
}).then((jsonResult) => {
// Do something with the result
if ( jsonResult.err )
reject(jsonResult);
console.log(jsonResult);
resolve(jsonResult);
});
});
}
It provides this error.
Failed to load http://example.com/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
On the PHP side, I am using a simple output to ensure nothing else is going wrong causing the error on the server's side.
<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: http://example.com');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-Type, Authorization, x-requested-with');
echo json_encode(['data'=>'result']);
?>
I have followed many questions, but most notably this question with a very thorough explanation of the issue and possible solutions.
For now, I am just using the tried-and-true $.ajax() to complete this task, but I am wanting to fully understand the fetch() API to the extent necessary to replicate this functionality as it seems like something very basic from my experience.
In your PHP code, you've specified header('Access-Control-Allow-Origin: http://example.com');. This is wrong - you need to specify the value passed in the Origin request header (which in your case would be http://localhost:3000):
header('Access-Control-Allow-Origin: http://localhost:3000');
Ideally you wouldn't hardcode it - you'd just extract the Origin request header and pass that back.
BTW, I believe that JQuery's $.Ajax uses fetch() under the covers (just like XmlHTTPRequest()). Basically, everything uses fetch...

Set headers to GET/POST request

We want to send authentication token and signature during GET/POST request. We are not preferring to send security information through body Or parameter. So we decided to send through headers in request.
When we googled we got to know that we can do this using ajax post request. But we want to move to next pages with headers.
How we can implement this?
Edited:
We had plan to store these information on cookies. But in iPhone if cookies is disabled will change behaviour of our website. So to overcome we are planning to send through headers.
You can set X-AUTHENTICATION-TOKEN in ajax request something as below which I am using for a real time REST API call via ajax requests.
$.ajax({
type: "GET",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-AUTHENTICATION-TOKEN', 'token string');
},
The server side must set the header something as
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, X_AUTHENTICATION_TOKEN');
And to retrieve the data on server side you may have
if (isset($_SERVER['HTTP_X_AUTHENTICATION_TOKEN'])) {
$request_header = $_SERVER['HTTP_X_AUTHENTICATION_TOKEN'];
} else {
if (function_exists('getallheaders')) {
foreach (getallheaders() as $header_name => $header_value) {
if ($header_name == 'X_AUTHENTICATION_TOKEN') {
$request_header = $header_value;
}
}
}
}
So here $request_header will be the token and you can use this in the server side script for validation.

Creating a restful API using PHP as server and jQuery as client

I'm trying to create a Javascript client API service which calls the API of my site. This will be cross domain and i'm aware of the problems this causes. However, I need the user to send through some user credentials (whether that be their username and password encoded obviously or an API key + secret) so that I can return user specific details.
I initially looked at using the jsonp datatype however this doesnt allow you to set any custom headers so ruled this out.
I've been searching the web for a while and been unable to find a secure way of doing this cross domain, has anyone had any success with this and can give me some advice?
UPDATE:
I've tried this following code as suggested by lu1s, however I get an alert of 'boo' as stated n the error function..
$.ajax({
url: 'http://www.dotsandboxes.co.cc/__tests/cors.php',
type: 'GET',
dataType: 'json',
success: function() { alert('hello!'); },
error: function() { alert('boo!'); },
beforeSend: function (xhr) {
xhr.setRequestHeader('securityCode', 'Foo');
xhr.setRequestHeader('passkey', 'Bar');
}
});
Thanks
You can. Try adding the Allow-Access-Control-Origin: * to your HTTP response headers, as well as the correct content-type.
Try with a simple PHP script like this:
<?php
header('Access-Control-Allow-Origin: *');
header('Content-type: text/json');
echo json_encode(array('success'=>true,'data'=>'foobar'));
?>
Check this site to read more info about cross-origin: http://enable-cors.org/
About the authentication, it's NOT recommended to send usernames or passwords, even if they're encrypted. As you stated, it's better to pass a token in the URL. Best if following standards like http://oauth.net/2/ .

Categories