I'm having issue with site. I need to use XMLHttpRequest to send GET request to my api running on Node.js
The Issue is that when I do the request it doesn't send the payload. It's just an empty object. If I do the same without the XMLHttpRequest, for example in Postman everything works.
This is my XMLHttpRequest Function:
// AJAX Client (for RESTful API)
app.client = {}
// Interface for making API calls
app.client.request = function(headers,path,method,queryStringObject,payload,callback){
// Set defaults
headers = typeof(headers) == 'object' && headers !== null ? headers : {};
path = typeof(path) == 'string' ? path : '/';
method = typeof(method) == 'string' && ['POST','GET','PUT','DELETE'].indexOf(method.toUpperCase()) > -1 ? method.toUpperCase() : 'GET';
queryStringObject = typeof(queryStringObject) == 'object' && queryStringObject !== null ? queryStringObject : {};
payload = typeof(payload) == 'object' && payload !== null ? payload : {};
callback = typeof(callback) == 'function' ? callback : false;
// For each query string parameter sent, add it to the path
var requestUrl = path+'?';
var counter = 0;
for(var queryKey in queryStringObject){
if(queryStringObject.hasOwnProperty(queryKey)){
counter++;
// If at least one query string parameter has already been added, preprend new ones with an ampersand
if(counter > 1){
requestUrl+='&';
}
// Add the key and value
requestUrl+=queryKey+'='+queryStringObject[queryKey];
}
}
// Form the http request as a JSON type
var xhr = new XMLHttpRequest();
xhr.open(method, requestUrl, true);
xhr.setRequestHeader("Content-type", "application/json");
// For each header sent, add it to the request
for(var headerKey in headers){
if(headers.hasOwnProperty(headerKey)){
xhr.setRequestHeader(headerKey, headers[headerKey]);
}
}
// If there is a current session token set, add that as a header
if(app.config.sessionToken){
xhr.setRequestHeader("token", app.config.sessionToken.id);
}
// When the request comes back, handle the response
xhr.onreadystatechange = function() {
if(xhr.readyState == XMLHttpRequest.DONE) {
var statusCode = xhr.status;
var responseReturned = xhr.responseText;
// Callback if requested
if(callback){
try{
var parsedResponse = JSON.parse(responseReturned);
callback(statusCode,parsedResponse);
} catch(e){
callback(statusCode,false);
}
}
}
}
// Send the payload as JSON
var payloadString = JSON.stringify(payload);
xhr.send(payloadString);
};
This is code from when I make the request:
app.loadCartViewPage = function(){
var emailAdress = typeof(app.config.sessionToken.emailAdress) == 'string' ? app.config.sessionToken.emailAdress : false;
if(emailAdress){
var queryStringObject = { 'emailAdress' : emailAdress };
app.client.request(undefined, 'api/users', 'GET', queryStringObject, undefined, function(statusCode, responsePayload){
if(statusCode == 200){
var cartId = typeof(responsePayload.carts) == 'object' && responsePayload.carts instanceof Array ? responsePayload.carts[0] : [];
var payload = {'emailAdress' : emailAdress, 'cartId' : cartId };
app.client.request(undefined, 'api/carts', 'GET', undefined, payload, function(statusCode, responsePayload){
console.log(responsePayload);
});
} else {
app.logUserOut();
}
});
} else {
app.logUserOut();
}
};
The first GET request goes through as it should where I pass only queryString, but the second sends just empty objects.
Thanks for help in advance
XMLHttpRequest does not send a body for a GET or HEAD request. Arguments or options for those requests should be in query parameters, not in the body.
Here's a note from the MDN page on .send():
send() accepts an optional parameter which lets you specify the request's body; this is primarily used for requests such as PUT. If the request method is GET or HEAD, the body parameter is ignored and the request body is set to null.
Related
I'm writing a plugin that will intercept all the requests and responses and will extract data and if needed also modify the response. Below is the code I'm using to intercept the request, but it seems I can only read the response and not modify it. The code is injected into the page by manifest.json.
(function(xhr)
{
var XHR = XMLHttpRequest.prototype;
var send = XHR.send;
XHR.send = function(postData)
{
this.addEventListener('load', function()
{
if (postData)
{
if (typeof postData === 'string')
{
try
{
this._requestHeaders = postData;
} catch (err)
{
console.log(err);
}
}
else if (typeof postData === 'object' || typeof postData === 'array' || typeof postData === 'number' || typeof postData === 'boolean')
{
var enc = new TextDecoder("utf-8");
requestdata = enc.decode(postData);
console.log("postData");
var json = JSON.parse(requestdata);
console.log(json);
// Extract data from request
var req = this.responseText
// Change req, this does nothing!
this.responseText = req;
}
}
});
return send.apply(this, arguments);
};
})(XMLHttpRequest);
I understand this is because responseText is actually read only, and then property itself returns a cloned string, rather than a reference to actual response text. Is there any way around it? The only other way I see is using CEF, opening a web site from my CEF application and intercepting the requests there, which is nice, I can enhance the web site inside my application, but on the other hand it's cumbersome and I want my users to be able to download the plugin instead of having to use an exe.
Thanks!
In the below code when I try to hit the "/hello" route using the get method I am getting the following response. All the other routes are working fine except the "/hello" route using get method. Why is this happening?
var http = require('http');
var url = require('url');
var stringDecoder = require('string_decoder').StringDecoder;
var server = http.createServer(function(req,res){
//parse the URL and get the path if we pass true as paramater it will act as query string
var parsedURL = url.parse(req.url,true);
//Get the path alone
var path = parsedURL.pathname;
//Trimm the URL
var trimmedpath = path.replace(/^\/+|\/+$/g,'');
//Get the method
var method = req.method.toLowerCase();
//Get the headers
var headers = req.headers;
//get the querystring as an object
var queryStringObject = parsedURL.query;
//Get the payload if any
var decoder = new stringDecoder('utf-8');
var buffer = '';
req.on('data',function(data){
buffer += decoder.write(data);
});
req.on('end',function(){
buffer += decoder.end();
//Generate the data
var data = {
'method' : method,
'headers' : headers,
'trimmedpath' : trimmedpath,
'queryStringObject' : queryStringObject
}
var Handler = routes[trimmedpath];
var chosenHandler = typeof(Handler) !== 'undefined' ? Handler : handlers.notfound;
chosenHandler(data,function(statuscode,payload){
statuscode = typeof(statuscode) == 'number' ? statuscode : 300;
payload = typeof(payload) == 'object' ? payload : {};
console.log(payload);
var payloadString = JSON.stringify(payload);
//set the content type to view as object
res.setHeader('Content-Type','application/json');
res.writeHead(statuscode);
res.end(payloadString);
});
//Sending the response
console.log(buffer);
console.log(Handler,chosenHandler);
res.end("hello world");
});
});
var handlers = {};
handlers.hello = function(data,callback){
if(data.method == 'post'){
callback(404,{'Message' : 'You have hitted the post route'});
}
if(data.method == 'get'){
callback(143,{'message': 'you have hitted the get route'});
}
}
handlers.ping = function(data,callback){
callback(999,{'message':'ping route'});
}
handlers.notfound = function(data,callback){
callback(600,{'Message' : 'Major issue'});
}
var routes = {
'ping' : handlers.ping,
'hello' : handlers.hello
}
server.listen(3000,function(){
console.log("server started listening in the port 3000");
});
I have split the messages based on the method received from the request.
It looks like you're comparing HTTP method in small
handlers.hello = function(data,callback){
if(data.method === 'POST'){
callback(404,{'Message' : 'You have hitted the post route'});
}
if(data.method === 'GET'){
callback(143,{'message': 'you have hitted the get route'});
}
}
I'll suggest you to use some already built router to handle multiple cases without increasing code length.
Update
considering you're already lower casing http method, I can see hello is being called without modifying your code;
{ message: 'you have hitted the get route' }
[Function] [Function]
{ Message: 'You have hitted the post route' }
[Function] [Function]
And the response in POSTMAN.
I would like to pass access_token via HTTP header.
_xhr.setRequestHeader('x-customtoken', 'value');
When I want to get it on server it's value is null. I get it like this:
public final static String HEADER_SECURITY_TOKEN = "x-customtoken";
// ..
request.getHeader(HEADER_SECURITY_TOKEN)
Pass the token via header is the only solution for me. I can pass it like a request param, but I need to to it via HTTP-headers.
xhr: function(options){
var _xhr = new XMLHttpRequest(),
_to_send = options.params;
_xhr.open(options.type, options.url);
_xhr.setRequestHeader('Content-Type', 'application/json');
_xhr.setRequestHeader('x-customtoken', 'value');
_xhr.responseType = 'json';
_xhr.onload = function () {
if (_xhr.status === 200) {
var _json = _xhr.response;
if (typeof _json == 'string')
_json = JSON.parse(_json);
options.success(_json);
} else {
options.error(_xhr);
}
};
try {
_xhr.send(_to_send);
} catch (e){
options.error(_xhr);
}
}
I am trying to do native javascript and requesting an html page using the following JS code, why does it return (in Chrome) the following?
XMLHttpRequest cannot load /live-examples/temp.html. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
The code I am using is as follows:
var sendRequest = (function(){
// Private member variables
var readyState = {
UNSENT : 0,
OPENED : 1,
HEADERS_RECIVED : 2,
LOADING : 3,
DONE : 4
}
var status = {
SUCCESS : 200,
NOT_MODIFIED : 304
}
// Private member methods
function getData(callBack){
var xhr = getXhr();
if(!xhr){
console.log('unable to create xhr object.')
return false;
}
// test readyState
if(xhr.readyState !== readyState.DONE) return;
if(xhr.status === status.SUCCESS && xhr.status !== status.NOT_MODIFIED){
callBack(xhr.responseText);
}
}
function getXhr(){
var XMLHttpList = [
function(){ return new XMLHttpRequest(); },
function(){ return ActiveXObject("Msxml2.XMLHTTP"); },
function(){ return ActiveXObject("Microsoft.XMLHTTP"); }
], xhr;
for(var i = 0; i < XMLHttpList.length; i++){
try{
xhr = XMLHttpList[i];
break;
}catch(e){
continue;
}
}
return xhr();
}
return function(url, callBack, postData){
var xhr = getXhr();
if(!xhr) return;
var method = (postData) ? 'POST' : 'GET';
xhr.open(method, url, true);
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded');
xhr.onreadystatechange = getData(callBack);
xhr.send(postData);
};
})();
function dealWithResponse(response){
// the response from the xhr request
console.log('success response: ' + response);
}
// cross origin request error.
$(function(){
document.getElementById('MyID').onclick = function(){ sendRequest('/live-examples/temp.html', dealWithResponse, 'GET'); }
});
HTML code within the BODY is as follows:
<button id="MyID">I have a button!</button>
I checked the the file 'temp.html' does exist.
I am in this code just trying to show some simple ajax call using native javascript in a talk I am due to present.
Many thanks in Advance,
Quinton :)
You need to use HTTP when you want to access data using the XMLHTTPRequest object.
I have the following JavaScript class:
var Server = function(onError)
{
/* public As, onError; */
var that, Key, Headers;
this.__construct = function()
{
that = this;
that.As = false;
that.onError = onError;
that.resetHeaders();
onError = null;
// Here I try to call the parent constructor (it seems I can't).
if(window.XMLHttpRequest)
that.XMLHttpRequest();
else
that.ActiveXObject('Microsoft.XMLHTTP');
}
this.Request = function(File, PostData, Function)
{
var Method, HeaderKey;
if(PostData == null)
Method = 'GET';
else
Method = 'POST';
try
{
that.open(Method, File, that.As);
/* Each request sets X-Requested-With to XMLHttpRequest by default.
If PostData is given, then we treat it's content type as a form.*/
that.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
if(PostData != null)
that.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
for(HeaderKey = 0; HeaderKey < Headers.length; HeaderKey++)
that.setRequestHeader(Headers[ HeaderKey ].Name, Headers[ HeaderKey ].Value);
if(Function != null)
that.onreadystatechange = function()
{
if(that.readyState == 4 && that.status == 200)
Function.call();
}
that.send(PostData);
}
catch(Exception)
{
if(that.onError != null)
that.onError(Exception);
}
}
this.addHeader = function(Name, Value)
{
Headers[ Key ] = {};
Headers[ Key ].Name = Name;
Headers[ Key ].Value = Value;
Key++;
}
this.resetHeaders = function()
{
Headers = [];
Key = 0;
}
this.__construct();
}
if(window.XMLHttpRequest)
Server.prototype = new XMLHttpRequest();
else
Server.prototype = new ActiveXObject('Microsoft.XMLHTTP');
Server.prototype.constructor = Server;
Where I make an inheritance depending on the state of the window.XMLHttpRequest var. In the __construct method I re-check this again for call the parent constructor.
I don't know if this is the correct form, but I would like that anyone could tell me what's wrong in here. By the way, when I check the console in Chrome I get the following exception: "Uncaught TypeError: Object [object Object] has no method 'XMLHttpRequest'", so I assume that it is not identifying the correct reference, however, I can see that all the properties / methods are present when I put the "." in the console, but I can't get access from a internal / external way (this is commenting the parent constructor condition). Thank you, I'll wait for your replies.