Following scenario. I have a simple login-form for username and password.
Wher the user clicks the login-button the form is posted to the server which is checking the credentials. When they are okay, a redirect is made to the default landing-page.
For sending the form-data I have written the following:
static async postData<TResult>(options: { method: string, url: string, data?: any }): Promise<TResult> {
return new Promise<TResult>((resolve, reject) => {
try {
const xhr = new XMLHttpRequest();
xhr.onload = (): void => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(xhr.response);
} else {
reject(xhr.status);
}
}
};
xhr.withCredentials = true;
xhr.open(options.method, options.url, true);
xhr.send(options.data);
} catch (e) {
console.error(e);
}
});
}
which is called like:
const response = await postData({ method: theForm.method, url: theForm.action, data: formData })
.then(response => {
console.log(response);
})
.catch(reason => {
console.error(reason);
});
In Chrome and Firefox the response has an responseURL-property which I could use for setting window.location.url = xhr.responseURL; to redirect the page. But this wont work in IE as the response-type is something completely other.
On the other hand I have the complete HTML (which is the content of the redirect aka the landing-page) in xhr.responseText but I have no idea how I can use this?
I tried to replace the page-content as described here But this is throwing a bunch of errors in Chrome and IE it's not working at all showing
SCRIPT70: Permission denied
Some additional notes. I am using TypeScript to write the client-code which is targeted to es6 and afterwards transpiled using babel-loader to es5 via webpack.
I think you need try next code:
location.href = 'http://www.example.com' or
location.assign("http://www.mozilla.org"); // or
location = "http://www.mozilla.org";
Related
I created one chrome plugin for doing some analysis on the data in the page, for that i need to call some API's from the plugin and i want to give some custom user-agent for that to identify it from server, cant use any other keys in header it will increase the workload as it's already available API for some other applications
I Tried 3 methods and all i am getting is some error message and default chrome user-agent, if i change the key name from user-agent to any other name its working fine, but i want to send it in user-agent key only
var xhr = new XMLHttpRequest();
xhr.open('GET', url, false, "username", "pass");
xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8');
xhr.setRequestHeader('User-Agent', 'plugin');
console.log(url)
xhr.onreadystatechange = function () {
if (xhr.readyState != 4) return;
if (xhr.status != 200 && xhr.status != 304) {
setMessageBlock('10008', "Sorry. Error occurred while fetch product URL. Please try again later", "error")
messageblock();
return;
}
response = JSON.parse(xhr.responseText);
}
xhr.send();
return response;
this is givng some error like
Refused to set unsafe header "User-Agent"
Then i Tried this as well
fetch(url, {
method: "GET",
headers: {"Content-type": "application/json;charset=UTF-8", "user-agent": "plugin"}
})
.then(response => {
console.log(response.text())
// handle the response
})
.catch(error => {
// handle the error
});
this is not giving any error but sending default user-agent
Tried one more method by changing background.js
chrome.webRequest.onBeforeSendHeaders.addListener(
console.log("befire dadad")
function(info) {
// Replace the User-Agent header
var headers = info.requestHeaders;
headers.forEach(function(header, i) {
if (header.name.toLowerCase() == 'user-agent') {
header.value = 'catalog_plugin';
console.log('change')
}
});
return {requestHeaders: headers};
},
// Request filter
{
// Modify the headers for these pages
urls: [ "<all_urls>" ],
// In the main window and frames
types: ["main_frame", "sub_frame"]
},
["blocking", "requestHeaders"]
);
this also not working as expected.
Please any one suggest me a solution for this
Here is my router
router.post("/login", async (req, res) =>
{
try
{
const user = await User.findByCredentials(req.body.email, req.body.password)
// console.log(user)
const token = await user.generateAuthToken()
// console.log(token)
res.redirect("/takvim")
}
catch(e)
{
res.status(400).redirect("/")
}
})
Here is my user model that I use in the function above
UserSchema.methods.generateAuthToken = async function ()
{
const user = this
const token = jwt.sign({_id: user._id.toString()}, "secret")
user.tokens = user.tokens.concat({token})
await user.save()
return token
}
UserSchema.statics.findByCredentials = async function (emails, passwords)
{
const user = await User.findOne({email: emails})
console.log(user)
const isMatch = await bcrypt.compare(passwords, user.password)
if(!isMatch)
{
throw new Error("unable to login")
}
return user
}
I am making the request from frontend using a button
$uyeolForm.addEventListener("submit", () =>
{
if(!$uyeolFormEmail.value.includes(".com"))
{
return $uyeolFormHata.innerHTML = "email geçersiz"
}
const xhr = new XMLHttpRequest();
let form = JSON.stringify({
email: $uyeolFormEmail.value,
password: $uyeolFormPassword.value
});
xhr.open("POST", "/login")
xhr.setRequestHeader('Content-type', 'application/json')
xhr.send(form);
})
Problem is when I am using the postman, application redirects me to the page i want and doesn't give an error.
When I send the request with button it still finds user but it doesn't redirect me to the page I expect and in the console i see the user(expected) and null which is not expected.
Thanks to everyone.
You are making an HTTP request with XMLHttpRequest when a submit event is triggered but you aren't preventing the default behaviour of a form submission.
So the XMLHttpRequest object is created and makes a request and then immediately after (and possibly cancelling the request depending on how quickly things go) the <form> is submitted to the URL specified in the action.
You said the endpoint was being hit twice, once where you get the user you expect and ones where you don't.
When you get the user you expect it is from the XHR submission.
When you don't, that is from the regular form submission (which won't be JSON encoded as HTML forms don't support JSON encoding so it doesn't find the user because it doesn't decode the data in the form correctly).
Since you said you wanted to redirect, don't use Ajax. Ajax is a method for making an HTTP request without leaving the current page.
Change the server-side code to accept the data in the format the <form> is encoding it (probably application/x-www-form-urlencoded unless you changed it with the enctype attribute).
You want to know what's the error message, always. Add a console.error(JSON.stringify(e))
before the response, and tell us what does it say.
catch(e)
{
console.error(JSON.stringify(e));
res.status(400).redirect("/");
}
If You're going to use application/json and application/x-www-form-urlencoded to support both ajax and usual form submission way - You've to redirect it on frontend level by reading Location header:
$uyeolForm.addEventListener("submit", (event) => {
event.preventDefault();
if(!$uyeolFormEmail.value.includes(".com")) {
return $uyeolFormHata.innerHTML = "email geçersiz"
}
fetch('/login', {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: $uyeolFormEmail.value,
password: $uyeolFormPassword.value
})
})
.then(function(response) {
if (response.redirected) {
const redirectTo = response.headers.get('Location');
if (redirectTo) {
window.location.href = redirectTo;
return;
}
}
})
.catch(function(error) {
alert(error.message);
});
})
keep in mind that to support both application/json and application/x-www-form-urlencoded You've to attach 2 body parsers as middleware:
const bodyParser = require('body-parser');
router.use(bodyParser.urlencoded(true));
router.use(bodyParser.json());
the error occur when i try to download anything bigger than 50kb. I tried a lot of ways: using standard angular http client, xhr request, xhr request in zone.runOutsideAngular. But seams to get the same mistake every time. But when i tested same request from vanilla javascript it worked like a charm. Text of my request looks like this.
this.zone.runOutsideAngular(() => {
let url = environment.backEndHttpsUrl + 'some_backend_path';
this.xhr.withCredentials = true;
this.xhr.responseType = 'blob';
this.xhr.open('GET', url, true);
const fileName = 'some name constructing method';
this.xhr.onload = () => {
console.log(this.xhr.response);
let blob = this.xhr.response;
FileSaver.saveAs(blob, fileName);
};
this.xhr.send();
});
method using angular httpClient :
return this.http.get(environment.backEndHttpsUrl + 'some request building logic',
{
withCredentials: true,
responseType: 'blob',
}).toPromise()
I am creating the front end of an application using Angular 2 and I am trying to load an image from a third party site using XMLHttpRequest.
My code is below:
loadFile(fileUrl) {
const promise = new Promise((resolve, reject) => {
const request = new XMLHttpRequest();
request.open('GET', fileUrl, true);
request.setRequestHeader('Accept', 'image/jpeg');
request.onload = () => {
if (request.status === 200) {
resolve(request);
}
else {
reject(Error(request.statusText));
}
};
request.onerror = () => {
reject(Error('Network error.'));
};
request.send();
});
return promise;
}
And this is the code that I am using to test it:
import FileHelper from './file-helper';
describe('File Helper', () => {
it('should retrieve the contents of an image on the web', (done) => {
let fileLoadPromise, fileContent;
fileLoadPromise = FileHelper.loadFile('http://adsoftheworld.com/files/steve-jobs.jpg');
fileLoadPromise.then((request: XMLHttpRequest) => {
fileContent = request.responseText;
expect(request.responseType).toEqual('image/jpeg');
done();
}).catch(error => {
console.log(error);
done.fail();
});
expect(fileContent).toBeTruthy();
});
});
I've looked around the internet and several pages said that I should add image/jpeg to my headers, so I did it using this: request.setRequestHeader('Accept', 'image/jpeg');, however I still get the error below whenever I run this code:
XMLHttpRequest cannot load http://adsoftheworld.com/files/steve-jobs.jpg. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9876' is therefore not allowed access.
Can anyone help me?
The problem you are facing is called CORS, https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
By giving header Access-Control-Allow-Origin:*, you will be able to access the image through ajax, but the question is why ajax? just use img tag right?
<img src="http://adsoftheworld.com/files/steve-jobs.jpg"/>
var open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, uri, async, user, pass) {
this.addEventListener("readystatechange", function(event) {
if(this.readyState == 4){
var self = this;
var response = {
method: method,
uri: uri,
responseText: self.responseText
};
console.log(response);
} else {
console.log(this.readyState);
}
}, false);
open.call(this, method, uri, async, user, pass);
};
I am trying to listen for XHR before they are being sent. Something similar to jQuery's beforeSend in the $.ajax method.
My goal is to listen for all XHR's before they are being sent. I suppose the closest thing would be to check above if this.readyState === 1?
Would the code above cause any ajax libraries like jQuery to malfunction because I use prototype on XMLHttpRequest?
I am trying to listen for XHR before they are being sent.
Then try to spoof the send() method, not the open() one.
Would the code above cause any ajax libraries like jQuery to malfunction because I use prototype on XMLHttpRequest?
No, not really. Only,
it won't work where those libs choose not to use XMLHttpRequest (particularly IE)
…and even fail if the browser does not support the XMLHttpRequest object (or does not support accessing or modifying its prototype)
libs might be able to work around your spoof by dereferencing the functions before you can (though I don't know any common lib that does)
Your code calls the native method with a fixed number of arguments, not sure if that affects anything, and it does not re-return the result (even if we know it's undefined). To be 100% sure, use return open.apply(this, arguments);.
You need to insert this script as a DOM element, but the following code is what works for me for 90% of all network requests:
response_interceptor.js
(function () {
console.log('🔫 REQUEST INTERCEPTOR INJECTED');
let CE_id = 'Your Chrome Extension ID';
let WithNetworkPayload;
let gotResponse = false;
let job_network_payload = [];
let job_network_urls = [];
var XHR = XMLHttpRequest.prototype;
var send = XHR.send;
var open = XHR.open;
XHR.open = function (method, url) {
this.url = url; // the request url
request_list.push({
request: this,
args: arguments,
});
job_network_urls.push(url);
return open.apply(this, arguments);
};
//Get response from chosen request
XHR.send = function () {
this.addEventListener('load', function () {
console.log('Got Response 🤯');
console.log(this);
try {
this.response
.text()
.then((res) => {
job_network_payload.push({ endpoint: this.url, payload: res });
console.log(res);
})
.catch((err) => {
job_network_payload.push({ endpoint: this.url, payload: err });
console.log('❌ Error on getting response.Text()');
console.log(err);
});
} catch (err) {
console.log('❌ Error on getting response.Text()');
console.log(err);
job_network_payload.push({
endpoint: this.url,
payload: this.response,
});
}
//sendResponsetoBackground(this.response);
});
return;
};
})();
Use a common contentScript.js to add response_interceptor.js as a DOM element:
contentScript.js
function inject_response_interceptor() {
function interceptData() {
var xhrOverrideScript = document.createElement('script');
xhrOverrideScript.type = 'text/javascript';
xhrOverrideScript.src = chrome.runtime.getURL(
'./injected_scripts/response_interceptor.js'
);
document.head.prepend(xhrOverrideScript);
}
let interval = setInterval(() => {
if (document.head) {
clearInterval(interval);
interceptData();
}
}, 100);
}
inject_response_interceptor();
In the manifest dont forget to add the contentScript.js to be injected at documentStart:
manifest.js
...
"content_scripts": [{
"matches": ["http://*/*", "*://*/*"],
"run_at": "document_start",
"js": ["contentScript.js"]
}]