SOLVED: Cannot receive POST-request from JS

Hey,
i’m currently working on a project, where i have to pass data from a JS client to a CakePHP server.
I’m trying to do this via POST request, but the request isn’t even recevied by the controller.
For this i’m running XAMPP localy on my computer.

In JS: (used absolute path to be absolutly sure, the right function gets called, gonna change that in the end of course)

$.post(‘http://localhost:8008/ersatzteiltool/transferData’, cmd.payload, function(response) {
alert(‘succsess!’)
}, ‘json’);

I’m simply trying to pass some formatted JSON-Data (cmd.payload) to CakePHPs remoterender Controller (using an alternative route see below).

For routing in routes.php

$routes->connect(‘/transferData’, [‘controller’ => ‘remoterender’, ‘action’ => ‘orderSubmit’]);

and in RemoteRenderController.php

public function orderSubmit() {
$this->layout = null;
$jsonData = $this->request->input(‘json_decode’);
//or
//$data = $this->request->getData();
Log::write(‘debug’, 'orderSubmit reached, data: ’ . $jsonData);
}

This way the orderSubmit()-Function isn’t even called. When i change my POST-Request to a GET-Request in JS, the Controller recieves the request, but there is only an empty array passed.

I tried different things already:

  • sending not JSON-formatted Data or simple data like

‘data[User][id]’:‘1234’, ‘data[User][name]’:‘John’

(still an empty array arriving with GET, nothing with POST)

  • using AJAX POST/GET Request (same result as now)
  • tried without using an alternativ route

Anybody got any ideas? Am i just missing the obvious? First time working with Php.

Ideas i had, but couldn’t get working:

  • disable cors (maybe its blocking POST-Requests from AJAX?)

Thank you for your help!

What scope is your route in?

in Controller/RemoteRenderController.php

class RemoteRenderController {
orderSubmit() {
}
}

You need to define your routes in config/routes.php
here is mine for reference:

I did that, but maybe if have to define more routes?

As it is i wrote in routes.php:

$routes->connect(’/transferData’, [‘controller’ => ‘remoterender’, ‘action’ => ‘orderSubmit’]);

The thing that still confuses me, is that if i send a get request the function is called… (same as when i just call the URL in a browser)

EDIT:
Chromes developer console tells a little bit more:
Failed to load resource: the server responded with a status of 403 (Forbidden).

EDITEDIT:
I think it’s a problem with the auth component, i guess i got no rights, because my js client isn’t logged in…
–> added to the beforeFilter function: $this->Auth->allow([‘orderSubmit’]);
but its still not working. Nevertheless forbidden access.

Considering it’s an xhr request, try setting the csrf token in the headers? you’ll need to change your ajax call to:

$.ajax({
  url: '', // add your url here
  headers: {
    'X-CSRF-Token': <?= json_encode($this->request->getParam('_csrfToken')); ?>
  }
  data: '' // your data here
}).done(function(response) {
  // Do stuff here
});
1 Like

Thanks for your fast replies!
I tried:
beforeSend: function (xhr) {
xhr.setRequestHeader(‘X-CSRF-Token’, $(’[name="_csrfToken"]’).val());
},
as parameter already, but gonna try yours as well.


I am confused, why is there a PHP snippet in the header? Shoud i pass it as a string? Or do you define the JS code in one of the “view”.php files?


Passed it as a string and at least i recevied it finally. Your great man, big thanks to you!


Well i guess it’s only passing because it didnt have the type=“post”… with that it’s still not working…

with get i am receving an array, but i’m not sure what the actual content is. logging only says array.

what does your current ajax call look like?

$.ajax({
url: ‘http://localhost:8008/ersatzteiltool/remoterender/orderSubmit’,
headers: {
‘X-CSRF-Token’: “<?= json_encode($this->request->getParam('_csrfToken')); ?>”
},
contentType: “application/json; charset=utf-8”,
dataType: “json”,
type: “post”,
data: JSON.stringify(cmd),
}).done(function(response) {
console.log(“POST got THROUGH :)”);
});

Hmm… may I note that your route says /transferData while your ajax call is requesting orderSubmit
Please make sure you are using the right url :stuck_out_tongue:
Or even better, use CakePHP’s url builder (along with the reverse routing capability)!

$.ajax({
  url: `<?= h($this->Url->build(['controller' => 'RemoteRender', 'action' => 'orderSubmit'])); ?>`,
  // ... rest of your ajax stuff
})

https://book.cakephp.org/3.0/en/views/helpers/url.html

1 Like

Interesting Idea! I’ll try it.

Yeah sorry, in the meantime i changed the route in routes.php to:
$routes->connect(’/remoteRender’, [‘controller’ => ‘remoterender’, ‘action’ => ‘index’, ‘orderSubmit’, ‘userRedirect’]);

just trying out different things…

Just make sure that either:

  1. your array in the url builder matches the one in your route
  2. your url matches your scope

Example given:

case 1.:

// config/routes.php
Router::scope('/', function (RouteBuilder $routes) {
  $routes->connect('/myRoute', ['controller' => 'MyController', 'action' => 'index']);
});
// script.js
$.ajax({
  url: `<?= h($this->Url->build(['controller' => 'MyController', 'action' => 'index'])); ?>`,
  // ... rest of the ajax stuff
})

case 2.:

// config/routes.php
Router::scope('/', function (RouteBuilder $routes) {
  $routes->connect('/myRoute', ['controller' => 'MyController', 'action' => 'index']);
});
// script.js
$.ajax({
  url: `/myRoute`,
  // ... rest of the ajax stuff
})

Recommendation:

Use option 1 as this allows you to change the url without changing the route itself.
So let’s say you want to change the /myRoute part to /asdf, you can do so without having to change your views (and thus prevent potential breakage of your app).
The url builder will match the array you’ve given it and spit out the right url!

Try axios js. Remember to add csrfToken to the header. Example.

axios.defaults.headers.common[‘X-CSRF-Token’] = “<?php echo $this->request->getParam('_csrfToken'); ?>”;
axios.defaults.headers.common[‘Cache-Control’] = “no-store, private, no-cache, must-revalidate”;
axios.defaults.headers.common[‘Expires’] = 0;

axios.post(‘your controller/service method/optional pass data’, {data:{key:value data to the server}})
.then(function (response) {//process response

})
.catch(function (error) {//Catch that nasty error from the server

});

Thanks for your help!
Tried FinlayDaG33ks solution and njuejohns with axios, now if i log the error object from a axios request i get:
Error: “Request failed with status code 403”
exports https://unpkg.com/axios/dist/axios.min.js:8
exports https://unpkg.com/axios/dist/axios.min.js:8
onreadystatechange https://unpkg.com/axios/dist/axios.min.js:8
logAjaxRequest http://localhost:8008/debug_kit/js/toolbar.js?1561463013:74

I managed to decode the recevied data from the get-request, problem is, i initally wanted to send some encoded image files, as i know i can’t do that with a get-request because of the limited url size?

Why on earth would you want to upload an image using a GET request :stuck_out_tongue:
We have PUT for that stuff :stuck_out_tongue:
Also, you might want to send the data chunked in order to not hit a POST-size limit randomly…

Yeah as i said, i want to send my images with a POST (PUT would be fine aswell) request, but i really cant get it working with CakePHP.

I don’t want to send data with a get request, thats litterly not what the request is made for,b ut at the moment its the only way i can receive data at all…

What do your logs have to say about the cause of the 403 error? Those don’t typically happen without leaving some details.

I think that if all this stuff doesn’t work, you have something else causing the 403…
What is the output you’re getting?
Like, when I get an error, I get a huge red screen in my face telling me exactly what went wrong…

I think you need to set $this->autoRender to false and $this->layout to false.

Well, probably i should have started with looking into the error.log files…
it says CSRF token mismatch.
In this thread there were some suggestions how to send a valid CSRF header.

I tried so far using ajax:
headers: { 'X-CSRF-Token': <?= json_encode($this->request->getParam('_csrfToken')); ?> }
and axios:

axios.defaults.headers.common[‘X-CSRF-Token’] = “<?php echo $this->request->getParam('_csrfToken'); ?>”;

the log says with both ways CSRF token mismatch.

I added in the Application.php a new CsrfProtectionMiddleware for the middlewareQueue, no changes.