I am writing some code to intercept and log ever XHR request sent over JavaScript, but I am unable to find where to access the request payload from. Is this possible to do? My code is below, this logs the url, method, and response, but no payload.
let oldXHROpen = window.XMLHttpRequest.prototype.open;
window.XMLHttpRequest.prototype.open = function (
method,
url,
async,
user,
password
) {
console.log("---hooked request---");
console.log({ url });
console.log({ method });
console.log(this);
this.addEventListener("load", function () {
console.log("load: " + this.responseText);
});
return oldXHROpen.apply(this, arguments);
};
Related
I'm unable to access the result of my query despite checking in browser network(xhr) and seeing the data is returned successfully from api. But I can't even console.log the returned data. Not sure what's going on.
Here's my code:
// const url='/../../_public/api/news.php'; // does not work
const url='https://jsonplaceholder.typicode.com/users/3' // works
let getHandle = () => {
return new Promise(function (resolve){
$.get(url, {endpoint: 'titles', param: 'titles'}, (response) => {
console.log(response);
resolve(response);
})
})
}
getHandle().then((res) => {
console.log(res);
})
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
The problem is your api url, you need to start the local dev server with your PHP backend and change the url to something like '/api/news.php'
// I tested your code with the json placeholder API and it works
I am currently trying to directly send an image via ngx-webcam without saving it to my backend server and send it to a Face Detection API via my node.js. The problem is that I keep getting an error for my header in my node.js file. How can I resolve this issue?
I noticed that the image url being passed is quite long. Could that be an issue?
Image url:
"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAHgAoADASIAAhEBAxE..."
My error is:
TypeError [ERR_HTTP_INVALID_HEADER_VALUE]: Invalid value "undefined" for header "Content-Length"
at ClientRequest.setHeader (_http_outgoing.js:473:3)
at FormData.<anonymous> (C:\Users\Roger\Documents\GitHub\angular-face-recognition-app\back-end\node_modules\form-data\lib\form_data.js:321:13)
at C:\Users\Roger\Documents\GitHub\angular-face-recognition-app\back-end\node_modules\form-data\lib\form_data.js:265:7
at C:\Users\Roger\Documents\GitHub\angular-face-recognition-app\back-end\node_modules\form-data\node_modules\async\lib\async.js:251:17
at done (C:\Users\Roger\Documents\GitHub\angular-face-recognition-app\back-end\node_modules\form-data\node_modules\async\lib\async.js:126:15)
at C:\Users\Roger\Documents\GitHub\angular-face-recognition-app\back-end\node_modules\form-data\node_modules\async\lib\async.js:32:16
at C:\Users\Roger\Documents\GitHub\angular-face-recognition-app\back-end\node_modules\form-data\node_modules\async\lib\async.js:248:21
at C:\Users\Roger\Documents\GitHub\angular-face-recognition-app\back-end\node_modules\form-data\node_modules\async\lib\async.js:572:34
at C:\Users\Roger\Documents\GitHub\angular-face-recognition-app\back-end\node_modules\form-data\lib\form_data.js:105:13
at FSReqWrap.oncomplete (fs.js:153:21)
Front end: Angular
Component file:
//captures image function
public handleImage(webcamImage: WebcamImage): void {
//stores it into webcamImageg variable
this.webcamImage = webcamImage;
//uses fda.sendImage function to send webcamImage to api via a service
this.fda.sendImage(this.webcamImage.imageAsDataUrl).subscribe(res => {});
}
Service file
sendImage(imgUrl){
console.log(imgUrl);
const obj = {
url: imgUrl
};
return this.http.post(`${this.uri}`, obj);
}
Backend: node.js
Route file
facedetAPIRoutes.route("/").post(function (req, res){
let imageUrl = req.body.url;
myFaceDetAPI.recognizeImg(imageUrl).then(function(result) {
// here is your response back
res.json(result);
});
});
Function file for api call: uses a promise
//I believe problem lies here somewhere
this.recognizeImg = (url)=>{
let requestString = "https://lambda-face-recognition.p.rapidapi.com/recognize";
let req = unirest("POST", requestString);
let imgURL = url;
let promise = new Promise(function(resolve, reject) {
unirest.post(requestString)
.header("X-RapidAPI-Key", API_KEY)
.attach("files", fs.createReadStream(imgURL))
.field("album", ALBUM_NAME)
.field("albumkey", ALBUM_KEY)
.end(result => {
console.log("successfully recognized image");
resolve(result.body) // giving response back
});
});
return promise;
}
You should try adding x-rapidapi-host and content-type headers.
.headers({
"content-type": "application/x-www-form-urlencoded",
"x-rapidapi-host": "lambda-face-recognition.p.rapidapi.com",
"x-rapidapi-key": "",
"useQueryString": true
})
I am trying to add a custom header on all network requests going from application and I am trying to do this via service worker fetch.
The content of header needs to come from app(client), so I need to wait for a response from client before responding to any event.
Below is my attempt to achieve this
Here is my fetch listener code
function send_message_to_client(client, msg){
return new Promise(function(resolve, reject){
var msg_chan = new MessageChannel();
msg_chan.port1.onmessage = function(event){
if(event.data.error){
reject(event.data.error);
}else{
resolve(event.data);
}
};
client.postMessage("SW Says: '"+msg+"'", [msg_chan.port2]);
});
}
self.addEventListener('fetch', function (event) {
event.waitUntil(async function () {
const client = await clients.get(event.clientId);
send_message_to_client(client, "Pass Transaction Details")
.then(function (m) {
var req = new Request(event.request.url, {
method: event.request.method,
headers: event.request.headers,
mode: 'same-origin',
credentials: event.request.credentials,
redirect: 'manual'
});
var res_obj = JSON.parse(m);
req.headers.append('MY_CUSTOM_HEADER', res_obj.hdr_val);
return event.respondWith(fetch(req));
})
.catch(function (error) {
console.log("Error after event.respondWith call");
console.log(error);
});
}());
});
and here is how I registered this worker and its message listener
navigator.serviceWorker.register('/my-sw.js', {scope: '/'})
.then(function(reg) {
navigator.serviceWorker.onmessage = function (e) {
var msg_reply = {
"message" : "Replying to SW request",
};
msg_reply.hdr_val = sessionStorage.getItem('__data_val');
console.log("Replying with "+ JSON.stringify(msg_reply));
e.ports[0].postMessage(JSON.stringify(msg_reply));
};
}).catch(function(error) {
// registration failed
console.log('Registration failed with ' + error);
});
but apparently its shooting 2 requests, 1 original request and 1 with modified headers.
Any idea what am I doing wrong ? I am a newbie in javascript so pardon me if there is some stupid mistake.
From service worker debug console, I found that its going in catch block right after event.respondWith() call, so something wrong there probably ?
You must call FetchEvent.respondWith() synchronously in your fetch handler. In your code you are calling waitUntil() synchronously, but calling respondWith() later. By not calling respondWith() before returning from the fetch handler you are telling the browser to continue on with its normal networking path without interception.
I think you want something like this:
self.addEventListener('fetch', function (event) {
// call respondWith() here
event.respondWith(async function () {
const client = await clients.get(event.clientId);
send_message_to_client(client, "Pass Transaction Details")
.then(function (m) {
var req = new Request(event.request.url, {
method: event.request.method,
headers: event.request.headers,
mode: 'same-origin',
credentials: event.request.credentials,
redirect: 'manual'
});
var res_obj = JSON.parse(m);
req.headers.append('MY_CUSTOM_HEADER', res_obj.hdr_val);
// just return the response back to the respondWith() here
return fetch(req);
})
// You probably want to add a .catch() to return some reasonable fallback
// response.
In my Project when conditions are insufficient my Django app send JSON response with message.
I use for this JsonResponse() directive,
Code:
data = {
'is_taken_email': email
}
return JsonResponse(data)
Now I want using Javascript fetch API receive this JSON response and for example show alert.
I don't know how to use fetch API to do this. I want to write a listener who will be waiting for my JSON response from Django App.
I try:
function reqListener() {
var stack = JSON.parse(data);
console.log(stack);
}
var oReq = new XMLHttpRequest();
oReq.onload = reqListener;
I want to compare JSON from my Django app with hardcoded JSON:
For example:
fetch( 'is_taken_email': email) - > then make something
OR
receive JSON from my Django app and as AJAX make it:
success: function(data) { if (data.is_taken_email) { make something; }
Thanks in advance!
A fetch API is provided in the global window scope in javascript, with the first argument being the URL of your API, it's Promise-based mechanism.
Simple Example
// url (required)
fetch('URL_OF_YOUR_API', {//options => (optional)
method: 'get' //Get / POST / ...
}).then(function(response) {
//response
}).catch(function(err) {
// Called if the server returns any errors
console.log("Error:"+err);
});
In your case, If you want to receive the JSON response
fetch('YOUR_URL')
.then(function(response){
// response is a json string
return response.json();// convert it to a pure JavaScript object
})
.then(function(data){
//Process Your data
if (data.is_taken_email)
alert(data);
})
.catch(function(err) {
console.log(err);
});
Example using listener based on XMLHttpRequest
function successListener() {
var data = JSON.parse(this.responseText);
alert("Name is: "+data[0].name);
}
function failureListener(err) {
console.log('Request failed', err);
}
var request = new XMLHttpRequest();
request.onload = successListener;
request.onerror = failureListener;
request.open('get', 'https://jsonplaceholder.typicode.com/users',true);
request.send();
Example of Using Listener as setInterval (I'm not sure that you want to do something like this, it's just to share with you)
var listen = setInterval(function() {
fetch('https://jsonplaceholder.typicode.com/users')
.then(function(response) {
return response.json();
})
.then(function(data) {
if (data[0].name)
console.log(data[0].name);
})
.catch(function(err) {
console.log(err);
});
}, 2000);//2 second
I am not familier with Django, but I hope this could help you.
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"]
}]