The below code is used to work in chrome and suddenly stopped due to chrome recent change "Disallow sync XHR in page dismissal". The recent update on Crome early April 2019, I think Chrome 73.0.3683.103 stopped this feature and they have suggested sendBeacon or fetch keepalive. I will post what I was tried so this might help someone else.
https://www.chromestatus.com/feature/4664843055398912
$(window).on('beforeunload', function (e) {
//ajax call used work in Chrome
}
https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload
I know there are several related posts related to the same situation, but still couldn't find a solution. I tried several ways to make a server call.
Step 1:
$(window).on('beforeunload', function (e) {
if (navigator.sendBeacon) {
navigator.sendBeacon('url', 'data');
} else {
$.ajax({
type: 'POST',
url: 'url',
data: null,
contentType: 'application/json;',
async: false
});
}
}
This did not work due to content type - application-json
Step 2:
$(window).on('beforeunload', function (e) {
var data = { ajax_data: 22 };
var blob = new Blob([JSON.stringify(data)], {type : 'application/json'});
navigator.sendBeacon('url', blob);
}
This code did not work due to sendBeacon only support these content-types
multipart/form-data
application/x-www-form-urlencoded
text/plain
Step 3:
$(window).on('beforeunload', function (e) {
if (fetch) {
fetch(url, {
method: "POST", headers: { "Content-Type": "application/json" }
}).then(function (response) {
console.log(response.statusText);
}).then(function (response) {
console.log(response.statusText);
});
return false;
} else {
$.ajax({
type: 'POST',
url: 'url',
data: null,
contentType: 'application/json;',
async: false
});
}
}
This code works!. But only when you click on a link on the page or click on the Signout button. I need to work on this server method on when the user leaves the page on clicking on a link, signout, tab close and browser close.
Step 4:
$(window).on('beforeunload', function (e) {
e.stopPropagation();
e.preventDefault();
fetch('url', { method: 'POST', headers: { 'Content-Type': 'application/json' } });
}
This will show a popup "Leave site?", I don't want to the user to show any popup.
Step 5:
$(window).on('beforeunload', function (e) {
setTimeout(function ()
{
fetch('url', { method: 'POST', headers: { 'Content-Type': 'application/json' } });
}, 3000);
return false;
}
Also same as step 4, shows the "Leave site popup."
Now I'm running out of options and could not found a solution yet. Any help appreciated. I need a server call before page unloads by clicking on a link, logout, tab close, browser close. The above code will work if you put a breakpoint, which means it needs some time delay to send the server call before page unload. I don't mind putting a timeout if the user does not see any popup like "Leave site?"
This is an old question, but you need to use fetch with the keepalive flag set to true in the beforeunload event:
fetch(url, {
method: "POST",
keepalive: true,
headers: {
"Content-Type": "application/json"
}
});
sendBeacon does not behave the way documentation claims it does. In my testing, it did not respect the MIME type of a Blob in the request body, even if the Blob was a "supported" MIME type.
Use fetch instead. It gives you more control over the request headers, while guaranteeing that your request will be issued like sendBeacon supposedly does.
You might also need to bind the beforeunload event in the body of the page. A jQuery binding might not work for beforeunload.
Related
I am trying to make POST request in Cypress in order to perform auto login and redirect to dashboard page.
Here is the
Website link : https://admin-demo.nopcommerce.com
Error
The Code I have added to perform auto login is
Cypress.Commands.add('autologin', () => {
cy.clearCookies();
let options = {
method: 'POST',
url: 'https://admin-demo.nopcommerce.com/login?returnurl=%2Fadmin%2F',
headers: {
'authority': 'admin-demo.nopcommerce.com',
'Content-Type': 'application/x-www-form-urlencoded',
'origin': 'https://admin-demo.nopcommerce.com',
},
body: {
Email: 'admin#yourstore.com',
Password: 'admin',
__RequestVerificationToken:
'CfDJ8EoKK8bdbeVGtbyUmFkZjVXayQ00hwk5B6a1cPRgR3HvKKdGXLUNrX2hLPzPqPWV-RDY0zU-qaOalPnt9-fPC7xnshZqx1MMB_2aKitiCzSmm4CstnsQSi3YfrYGFzMVhck6tI02IznyqRUto2akvAA',
RememberMe: false,
},
};
cy.request(options).then(response => {
console.log(response);
});
});
Cypress.Commands.add('login', () => {
cy.autologin();
cy.visit('https://admin-demo.nopcommerce.com');
cy.get('#nopSideBarPusher').should('be.visible').click();
cy.get('#nopSideBarPusher').should('be.visible').click();
cy.clearCookies();
cy.get('.navbar-collapse .nav-link')
.eq(1)
.then(val => {
cy.get(val).click();
});
});
The purpose of __RequestVerificationToken is that it changes with every page refresh, so if you added this one string in there, it does make sense the server refused the whole request. There's a limited number of valid tokens at a given time, this one will likely be invalid by the time you're sending the request.
I'm trying to send form data from a NativeScript app to a TYPO3-Webservice.
This is the JavaScript I'm using:
httpModule.request({
url: "https://my.domain.tld/webservice?action=login",
method: "POST",
headers: { "Content-Type": "application/json" },
content: JSON.stringify({
username:username,
password:password
})
}).then((response) => {
console.log("got response");
console.log(response.content);
//result = response.content.toJSON();
callback(response.content.toJSON());
}, (e) => {
console.log("error");
console.log(e);
});
But I can't read this data in the controller. Even with this:
$rest_json = file_get_contents("php://input");
$postvars = json_decode($rest_json, true);
$postvars is empty. $_POST is empty, too (which is - according to some docs - because the data is sent as JSON and thus the $_POST-Array isn't populated.
Whatever I do, whatever I try, I can't get those variables into my controller.
I tried it with fetch as well as with formData instead of JSON.stringify, same result.
I might have to add, that when I add the PHP-part in the index.php of TYPO3, $postvars is being populated. So I guess something goes missing, until the controller is called.
Any ideas?
the nativescript part seems ok, your problem must be corrected in the server side.
i use similare call and its works
// send POST request
httpModule.request({
method: "POST",
url: appSettings.getString("SERVER") + '/product/list',
content: JSON.stringify(data),
headers: {"Content-Type": "application/json"},
timeout: 5000,
}).then(response => { // handle replay
const responseAsJson = response.content.toJSON();
console.log('dispatchAsync\n\tresponse:', responseAsJson);
}, reason => {
console.error(`[ERROR] httpModule, msg: ${reason.message}`);
});
I would like to disable cache on getting a request in vue environment. I already tried this but it does not work.
api.js (file)
getCall: () => {
return performAsyncGet(apiConfig.getCall.url,
requestConfigJSON, _REQUEST_TOKENS.getCall, apiConfig.getCall.cache)
.then(
response => response.data
);
},
(apiConfig.js) (file)
getCall: {
url: `${servicePathPrefixOrDomain}/api/getCall`
cache: false
}
Does anybody know how to disable the cache, when making a get request in vue.js?
Thanks in advance!
To avoid caching you can make your url unique by appending timestamp as a querystring parameter like this:
getCall: {
url: `${servicePathPrefixOrDomain}/api/getCall?_t={new Date().getTime()}`
cache: false
}
In this way for every ajax call the url will be unique due to different timestamp and browser will not cache the response.
Is solved adding the next code in the header:
const requestConfigJSON = {
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
}
};
I have a problem. My jquery submit function, tries to do a GET request, while I set it up as a POST request.
my submit function
function authenticate() {
var form = $('#form-login');
form.submit(function(evt) {
evt.preventDefault();
console.log('submitting!');
console.log(form.serialize());
$.ajax({
type: 'POST',
url: 'http://website.dev/loginz',
data: form.serialize(),
dataType: 'json',
success: function(data) { log_error(data.error); }
});
});
}
routes.php
Route::post('loginz', 'User\LoginController#authenticate');
What my chrome browser says
GET http://website.dev/loginz/ 405 (Method Not Allowed)
/Loginz
/* POST */
function authenticate(Request $request) {
$username = $request->input('username');
$password = $request->input('password');
if(Auth::attempt(['username' => $username, 'password' => $password])) {
redirect()->route('home'); /* should redirect to player */
}
return response()->json(['error' => trans('errors.user_password_combination').' => '.$username.' & '.$password]);
}
Maybe I am just stupid and hit a wall, I have stared myself to death and I just can't see the error :P
What version of laravel are you using?
Remind csrf token must be given for post requests.
you can disable the csrf verification also in \App\Http\Middleware\VerifyCsrfToken::class,
But would be better if you set in on the client side.
Meaning from laravel you should in the blade template add something like:
$( document ).ready(function() {
$.ajaxSetup({ headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' } });
});
But first, in Chrome (example) inspector -> network -> header: what is the request method?
The fault was an 301 redirect. The problem was created by myself. I added a redirect from non slash to slash (ex. /page to /page/) so the POST was redirected to a GET request.
I need to create a JSON ajax request from another domain. after I think I got over the cross domain issues, here is where I stuck:
I need to add my custom "myCustomHeader" header - that's easy from a server, but seems to be much more complicated from the client...
We added them
$.ajax({
type: 'POST',
data: put the results of your header request here,
url: 'http://server.com/service',
beforeSend: function (xhr) {
xhr.setRequestHeader('myCustomHeader', '1')
},
success: function(data) {
alert('success.');
}
});
This generates a preflight header with the headers I wanted, without the values (CSV), but they do not appear in the header of the request itself (as myCustomHeader=X)...
You can use CORS for this purpose.
Example code:
jQuery.support.cors = true;
function CrosDom_ajax(url) {
if (window.XDomainRequest
&& $.browser.msie
&& $.browser.version < 10) {
xdr = new XDomainRequest();
if (xdr) {
xdr.onload = function () {
alert(xdr.responseText);
};
xdr.open("get", url);
xdr.send();
}
}
else {
$.ajax({
url: url,
success: function (response) {
},
error: function (data) {
}
});
}
}
Also you need to Write the following code in server side, to allow cross domain access
Response.AppendHeader("Access-Control-Allow-Origin", "*");