$request->ajax() returns false on ajax call - javascript

I am making a ajax request with axios to a laravel controller, i want to use a middleware to check if the request was made with ajax, but the problem is that when i make an ajax request, the middleware throws false always.
i make the call like this
axios.post('/api/contact/send', {
...
data : data
}).then((response) => {
Do somethings
}).catch(err => {
Do somethings
})
my api routes
Route::namespace('Home')->middleware('IsAjaxRequest')->domain(env('HOST'))->group(function(){
....
Route::post('contact/send','ContactController#postContact');
});
the IsAjaxRequest middleware
if(!$request->ajax()) {
abort(403, 'Unauthorized action.');
}
return $next($request);
and the controller
<?php
namespace App\Http\Controllers\Home;
use Illuminate\Http\Request;
use App\Events\Home\ContactMail;
use App\Http\Controllers\Controller;
use App\Http\Requests\ContactRequest;
class ContactController extends Controller
{
//
public function postContact(ContactRequest $request)
{
$data = $request->all();
event(new ContactMail($request->all()));
return response()->json();
}
}
if i take out the middleware, everything will work fine, the problem is when i check $request->ajax() that return false, i have checked it outside the middleware directly in the controlelr but the result is the same, what's wrong? why return false if the call was made via ajax?

Axios does not send the X-Requested-With header that Laravel looks for to determine if the request is AJAX.
If you ask me you should not use or rely on this header at all but (I guess) for the purposes of easy migration away from jQuery (which does include the header) the basic Laravel boilerplate bootstrap.js has code:
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
which ensures all requests made with Axios get this header, however if you are not using that file you need to run this line in your own script.

Related

Send default POST variable in all Axios requests

I need to add the default global variable to all my POST requests using Axios.
I'm able to add the parameter using interceptor like:
axios.interceptors.request.use((config) => {
config.params = config.params || {};
config.params['timezone_adjust'] = window.timezone_adjust;
return config;
});
But in this case the url looks like "{url}?timezone_adjust=0
However I want to include the timezone_adjust variable on the request data object instead. Is that possible?
If you want to make a "global" settings to all your POST requests you should prefer using headers instead of body payload
Why? different requests may have different body payload, yet they can share common headers set (it is more common than shared payload)
In that case you can use Global axios defaults
axios.defaults.headers.post['YOUR-COMMON-HEADER'] = 'HEADER-VALUE';
Then you should fetch your headers from request object in your backend

How NOT to send back a response to ajax post call in node.js?

I have an ajax post call and I want to just send the form values without waiting for a response to come. I want to redirect from my express app and not form my client side. server-side:
router.post("/", (req, res)=>{
res.status(200).send(`signup/confirm-email?v=${req.body.email}`);
// i want to be able to rediect with res.redirect("signup/confirm-email?v=${req.body.email}")
};
});
client-side:
$.post('/signup', $('#signup-form-container form').serialize())
.done(lnk=>{
window.location.replace(`${window.location}${lnk}`); })
.fail(function(xhr){ //handle errors };
The code above works, it sends a response to ajax and then i redirect from client side.
I want to redirect from server-side.
I tried to redirect from my express app using res.redirect() but it doesn't work without logging any errors to the console and in the network tab in the dev tool, it shows that the request type is xhr. If there isn't a solution to this problem, than is there a way to hide the query in the route recieved. I don't want v=${req.body.email} to be displayed in the url bar. Thank you in advance.
The point of Ajax is that the request is made by JavaScript and the response is handled by JavaScript.
If you return a redirect response, then JavaScript will follow the redirect, make a new request, and handle the response to that.
If you don't want to handle the response with JavaScript: Don't use Ajax. Use a regular form submission instead.
Avoid using jQuery, it will almost always lead to bad practices and unmaintainable code.
You should use plain Javascript or React if you need a framework (which is mainly if you need to work on a big project, but may not be suited for total JS beginner). My solution here is in plain Javascript.
As a replacement for the jQuery request util ($.post(), etc ...), browsers have a very good HTTP request API named fetch (MDN). I use it in this solution.
If you don't want to show the email param in the URL, you can set it in the localStorage.
You cannot redirect directly from Express for a POST method. Only if you were trying to GET a page, Express could redirect to another GET (and so change the URL in your browser).
The only solution to your need is to use the window.location after receiving the response from your /signup endpoint.
Server-side:
router.post('/', function (req, res) {
const form = req.body.form
// your registration code here
// ...
res.json({
success: true,
email: form.email
})
})
Client-side:
signup.js
const form = {
email: document.getElementById('email').value
// add other fields you need
}
fetch('/signup', {
method: 'POST',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({ form })
})
.then(res => res.json())
.then(res => {
// Set the localStorage item so you can get it back
// in the JS script of /signup/confirm-email
localStorage.setItem('email', res.email)
// Redirect to the confirm email page
window.location = '/signup/confirm-email'
})
Client-side:
confirmEmail.js
const email = localStorage.getItem('email')
if (!email) window.location = '/signup'
// proceed with your code
Code for this answer

How to call a http request synchronously in angular 5

I want to call an http.post() request synchronously and after the response receive want to proceed with other code.
Or just want to hit the server but don't want to wait for the response.
Perhaps I'm just missing something, but that shouldn't be too hard if you're willing to ignore the response. If you're using angular, put somewhere at the top of your file:
import { HttpClient } from '#angular/common/http';
Then, in the constructor, include:
constructor(private http: HttpClient, ...) {
//...
}
Finally, in your code, just include the post request with an empty function after you get the result back:
this.http.post(url, requestBody, options).toPromise().then(() => {}).catch(error => {
console.error("Error: ", error);
});
Hope this helps!

Is it bad to 'RedirectToAction' when using AJAX POST? (ASP.NET)

I am new in learning jQuery, Json, Ajax.. and am trying to understand the concepts clearly, but having a little difficult time.
I have a ajax POST Delete method which is working, but my prof. has asked me to refactor the code in my Controller to better the overall performance.
This is my Delete in Controller
// POST: Course/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Course course = courseService.GetCourseByID(id);
courseService.DeleteCourse(id);
return RedirectToAction("Index");
}
And my ajax call
$('#dialog-box').on("click", '#confirm-del', function () {
var token = $('input[name="__RequestVerificationToken"]').val();
var data = { id: id, __RequestVerificationToken: token };
$.ajax({
type: "POST",
url: "#Url.Action("Delete","Course")",
data: data,
//ajaxasync: true,
success: function () {
$("#dialog").dialog("close");
$('div.table-content').empty().load('.table-content');
//console.log("success");
},
error: function () {
console.log("failed");
}
});
});
My prof. commented saying
"Delete Post ajax calls reloads page or goes to ajax? It looks like it reloads. Change color of some element in ajax to confirm it goes to the ajax call. It's unnecessary and if you have more logic after the ajax returns, you won't be able to do anything since you just reloaded the page."
And this was after asking for a clarification on what to do as I am not being able to fully comprehend the issue.
If I just return View() instead of the return RedirectToAction (Index) will it be better performance and take care of the issue the prof. is talking about?
Your professor is correct. You should not use RedirectToAction if you plan to call that Action Method via Ajax.
Instead, you need to return JsonResult. For example,
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Course course = courseService.GetCourseByID(id);
courseService.DeleteCourse(id);
return Json("Course was deleted successfully.");
}
FYI: if you really need to redirect to different page inside Ajax call in some rare cases, you can use JavaScriptResult.
return RedirectToAction("Index"); returns HTTP status 302 with the URL to redirect (Home/Index) in your case.
Since you are not handling this HTTP status in ajax handler (success handles 2XX codes and error 4XX and 5XX codes) the response is not handled on client side at all

Preventing HTTP Basic Auth Dialog using AngularJS Interceptors

I'm building an AngularJS (1.2.16) web app with a RESTful API, and I'd like to send 401 Unauthorized responses for requests where authentication information is invalid or not present. When I do so, even with an HTTP interceptor present, I see the browser-presented basic "Authentication Required" dialog when an AJAX request is made via AngularJS. My interceptor runs after that dialog, which is too late to do something useful.
A concrete example:
My backend API returns 401 for /api/things unless an authorization token is present. Nice and simple.
On the AngularJS app side, I've looked at the docs and set up an interceptor like this in the config block:
$httpProvider.interceptors.push(['$q', function ($q) {
return {
'responseError': function (rejection) {
if (rejection.status === 401) {
console.log('Got a 401')
}
return $q.reject(rejection)
}
}
}])
When I load my app, remove the authentication token, and perform an AJAX call to /api/things (to hopefully trigger the above interceptor), I see this:
If I cancel that dialog, I see the console.log output of "Got a 401" that I was hoping to see instead of that dialog:
Clearly, the interceptor is working, but it's intercepting too late!
I see numerous posts on the web regarding authentication with AngularJS in situations just like this, and they all seem to use HTTP interceptors, but none of them mention the basic auth dialog popping up. Some erroneous thoughts I had for its appearance included:
Missing Content-Type: application/json header on the response? Nope, it's there.
Need to return something other than promise rejection? That code always runs after the dialog, no matter what gets returned.
Am I missing some setup step or using the interceptor incorrectly?
Figured it out!
The trick was to send a WWW-Authenticate response header of some value other than Basic. You can then capture the 401 with a basic $http interceptor, or something even more clever like angular-http-auth.
I had this issue together with Spring Boot Security (HTTP basic), and since Angular 1.3 you have to set $httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest'; for the popup not to appear.
For future reference
I've come up with this solution when trying to handle 401 errors.
I didn't have the option to rewrite Basic to x-Basic or anything similar, so I've decided to handle it on client side with Angular.
When initiating a logout, first try making a bad request with a fake user to throw away the currently cached credentials.
I have this function doing the requests (it's using jquery's $.ajax with disabled asynch calls):
function authenticateUser(username, hash) {
var result = false;
var encoded = btoa(username + ':' + hash);
$.ajax({
type: "POST",
beforeSend: function (request) {
request.setRequestHeader("Authorization", 'Basic ' + encoded);
},
url: "user/current",
statusCode: {
401: function () {
result = false;
},
200: function (response) {
result = response;
}
},
async: false
});
return result;
}
So when I try to log a user out, this happens:
//This will send a request with a non-existant user.
//The purpose is to overwrite the cached data with something else
accountServices.authenticateUser('logout','logout');
//Since setting headers.common.Authorization = '' will still send some
//kind of auth data, I've redefined the headers.common object to get
//rid of the Authorization property
$http.defaults.headers.common = {Accept: "application/json, text/plain, */*"};

Categories

Resources