ablaszkiewicz1
ablaszkiewicz1

Reputation: 985

REACT + PHP - blocked my CORS policy only in POST request

Overview
My react app is hosted on githup-pages and a PHP API is hosted on a standard, paid hosting.

This works (GET)
When I started developing my app, I encountered a pretty popular error, which is Access to fetch at ... has been blocked by CORS policy. I have found a quick-fix which was to write this header("Access-Control-Allow-Origin: *") in the PHP's first lines and it worked. However those were the GET requests.

This doesn't work (POST)
This time I have a piece of code in which I have to use a POST request and need to access it's response. This is the piece of code responsible for sending the post request:

const editEvent = async () => {
    const requestOptions = {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', },
        body: JSON.stringify({ eventID: chosenEvent, courseID: courseID, groupID: groupID, time:time, date: date, description: description, typeID: typeID, password: password}),
        mode: 'cors',
    };
    const response = await fetch(`https://aleksanderblaszkiewicz.pl/kiedykolos/edit_event.php`, requestOptions);
}

It happened again - I am getting same error Access to fetch at ... has been blocked by CORS policy. Solution which I am using now is to use mode: 'no cors' but it doesn't let me to get the response as it is opaque. Another solution I have found is to add more headers:

header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Accept, Authorization, X-Requested-With, X-Auth-Token, Origin, Application");

But it doesn't work as well. Any suggestions? Full error code:

Access to fetch at 'https://aleksanderblaszkiewicz.pl/kiedykolos/add_event.php' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Full PHP code:

<?php
header("Access-Control-Allow-Origin: http://localhost:3000");
header("Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Accept, Authorization, X-Requested-With, X-Auth-Token, Origin, Application");
$servername = "...";
$username = "...";
$password = "...";
$dbname = "...";

$connection = new mysqli($servername, $username, $password, $dbname);
mysqli_set_charset($connection, 'utf8'); 

if ($connection -> connect_errno) {
  echo "Failed to connect to MySQL: " . $connection -> connect_error;
  exit();
}

$inputJSON = file_get_contents('php://input');
$input = json_decode($inputJSON, TRUE);

$courseID = $input["courseID"];
$groupID = $input["groupID"];
$date = $input["date"];
$time = $input["time"];
$description = $input["description"];
$typeID = $input["typeID"];
$password = $input["password"];

$sql = "INSERT 
        INTO `events` (`id`, `date`, `time`, `description`, `course_fk`, `year_group_fk`, `type_fk`)
        VALUES (NULL, '$date', '$time', '$description', '$courseID', '$groupID', '$typeID')";

if($password == "Ujebale321!") {
  $result = mysqli_query($connection, $sql) or die("Error in Selecting " . mysqli_error($connection));
  echo "Success";
}
else {
  echo "Wrong password";
}


mysqli_close($connection);
?>

Upvotes: 3

Views: 10499

Answers (2)

Sameer Swankar
Sameer Swankar

Reputation: 1

Add these lines in your php file and while calling the api in React JS use Axios instead of Fetch

header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Methods: HEAD, GET, POST, PUT, PATCH, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method,Access-Control-Request-Headers, Authorization");
header('Content-Type: application/json');
$method = $_SERVER['REQUEST_METHOD'];
if ($method == "OPTIONS") {
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Headers: X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method,Access-Control-Request-Headers, Authorization");
header("HTTP/1.1 200 OK");
die();
}

Upvotes: 0

rags2riches-prog
rags2riches-prog

Reputation: 1761

The issue is that your server set a number of allowed headers that are not part of the origin request. The only request header in your Fetch object is content-type: application/json, so must match the Access-Control-Allow-Headers in you server.

The Access-Control-Request-Headers header is used when issuing a preflight request to let the server know what HTTP headers will be used when the actual request is made (such as with setRequestHeader()). This browser side header will be answered by the complementary server side header of Access-Control-Allow-Headers.

Source Mozilla

This is a potential solution that will make your CORS request work:

  // In your code, this function is never called...
  const editEvent = async () => {
        const requestOptions = {
            method: 'POST',
            headers: { 'Content-Type': 'application/json', },
            body: JSON.stringify({ eventID: chosenEvent, courseID: courseID, groupID: groupID, time:time, date: date, description: description, typeID: typeID, password: password}),
        };
        await fetch(`https://aleksanderblaszkiewicz.pl/kiedykolos/edit_event.php`, requestOptions)
          .then(response => console.log(JSON.stringify(response)))
          .catch(error => console.log(error))


    }

This is a pre-flight request because the content-type is application/json. This means the browser make a "pre-request" to the server to see if the request can be executed (and the response be sent).

Thus, in your server-side code, you can only use:

   header("Access-Control-Allow-Origin: http://localhost:3000");

Or:

   header("Access-Control-Allow-Origin: *");

If you want to include another response header beside the Access-Control-Allow-Origin, allow just the content-type header, which is the one you set in your origin Fetch request:

   header("Access-Control-Allow-Headers: Content-Type");

Upvotes: 7

Related Questions