Ajax (Asynchronous JavaScript and XML) enables web application clients to send and receive data from the server asynchronously, without affecting the display of the current page.
Ajax uses JavaScript on client-side (in browser), and a server-side script (in this case PHP) that receives the Ajax request, and sends a response back to JavaScript.
When sending POST /PUT /DELETE requests to Laravel framework, it checks for a "csrf_token" which is a string automatically generated by Laravel.
So, when building Ajax applications with Laravel, you have to attach the CSRF token to every POST request, as a value in POST data, or in a header sent to server.
The csrf_token() function returns the CSRF token. To use it in your Ajax script, add, for example the "csrf_token" in a JavaScript variable, in HEAD section of the template file:
<head>
<title>Page Title</title>
<script>
var csrf_token ='{{csrf_token()}}';
</script>
</head>
Then, you can add the value of the csrf_token variable in the Ajax request.
- To add the "csrf_token" in POST data, attach it to the "_token" index in data sent to server:
function ajax(){
var req = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); // XMLHttpRequest object
var data ='_token='+ csrf_token;
//...
}
- Or, send the 'csrf_token' into a header with "X-CSRF-TOKEN":
function ajax(){
var req = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); // XMLHttpRequest object
req.open('POST', 'ajax/send', true); // set the request
//adds headers
req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
req.setRequestHeader('X-CSRF-TOKEN', '{{csrf_token()}}');
//...
}
- With jQuery:
headers: {
'X-CSRF-TOKEN': '+ csrf_token
},
Example Laravel - Ajax
1. Create a view blade file called resources/views/test_ajax.blade.php and copy the following code in that file.
<!doctype html>
<html lang="en">
<head>
<title>Laravel Ajax Test Example</title>
<script>
var csrf_token ='{{csrf_token()}}';
</script>
</head>
<body>
<h1>Laravel Ajax Test Example</h1>
<div id='see_resp'>
This message will be replaced with Ajax respose. A JSON array sent from server.<br>
Click the button to replace the message.
</div>
<button id='btn_ajax'>Test Ajax</button>
<script>
var see_resp = document.getElementById('see_resp');
//sends data to server, via POST, and displays the received answer
function ajaxReq(){
var req = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); // XMLHttpRequest object
//pairs index=value with data to be sent to server (including csrf_token)
var data ='_token={{csrf_token()}}&id=1';
req.open('POST', 'ajax/send', true); // set the request
//adds header for POST request
req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
req.send(data); //sends data
// If the response is successfully received, will be added in #see_resp
req.onreadystatechange = function(){
if(req.readyState ==4){
// alert(req.responseText); //just for debug
see_resp.innerHTML = req.responseText;
}
}
}
//register click event on #btn_ajax
document.getElementById('btn_ajax').addEventListener('click', ajaxReq);
</script>
</body>
</html>
If you use jQuery, replace the <script> before the ending </body> with this jQuery script:
2. Now, we create a controller called AjaxController. Copy the following code in app/Http/Controllers/AjaxController.php file.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class AjaxController extends Controller {
//Responds to requests to /ajax
//returns view() response
public function index(Request $request){
return view('test_ajax');
}
//Responds to post requests to /ajax/send
//receives the $request instance
//returns response with a JSON array, with input id, and Laravel version
public function send(Request $request){
//if required fields are received, and not empty
if($request->has(['id']) && $request->id!=null){
global $app;
return response()->json(['id'=>$request->id, 'version'=>$app::VERSION]);
}
else return 'Not valid id.';
}
}
3. To set the routes, add the following lines in routes/web.php.
//shows the ajax test page
Route::get('/ajax', 'AjaxController@index');
//when ajax request
Route::post('/ajax/send', 'AjaxController@send');
4. Visit the following URL to test this example.
//localhost:8000/ajax
- It will display a page with a content like in this Demo:
Laravel Ajax Test Example
This message will be replaced with Ajax respose. A JSON array sent from server.
Click the button to replace the message.
Handle expired tokens
If you want to keep alive a page with Ajax more than 120 minutes (which is default Laravel session lifetime), you should reinitialize the value of the csrf_token in javascript, because that token also will expire.
- For example, you can use this script that gets and stores the 'csrf_token' every 30 minutes.
1. In your view blade file:
<script>
//Laravel csrf_token used in Ajax requests
var csrf_token ='{{csrf_token()}}';
//get csrf_token from Laravel
function getCsrf(){
var req = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); // XMLHttpRequest object
req.open('POST', '/ajax/getcsrf', true); // set the request
//adds header for POST request
req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
req.setRequestHeader('X-CSRF-TOKEN', csrf_token);
req.send('_token={{csrf_token()}}'); //sends csrf_token
// If the response is successfully received, sets csrf_token
req.onreadystatechange = function(){
if(req.readyState ==4){
var resp = JSON.parse(req.responseText);
if(resp.csrf) csrf_token = resp.csrf;
}
}
}
//calls getCsrf() every 30 mintes
window.setInterval(getCsrf, 30*60*1000);
</script>
- Or, with jQuery:
<script>
//Laravel csrf_token used in Ajax requests
var csrf_token ='{{csrf_token()}}';
//get csrf_token from Laravel
function getCsrf(){
$.ajax({
type:'POST',
url:'/ajax/getcsrf',
headers: {
'X-CSRF-TOKEN': csrf_token
},
data:'_token='+ csrf_token,
success:function(resp){
if(resp.csrf) csrf_token = resp.csrf;
}
});
}
//calls getCsrf() every 30 minutes
window.setInterval(getCsrf, 30*60*1000);
</script>
2. In routes/web.php add this Route:
//ajax request for csrf_token. Returns json array with csrf_token value
Route::post('/ajax/getcsrf', function(){
return response()->json(['csrf'=>csrf_token()]);
});
- Also, consider to increase the lifetime session by changing the value of the 'lifetime' key in config/session.php file.