Modify jQuery Request Headers before send - javascript

I have a single page js app and I'm sending custom headers to my server containing logs, but i need to control the size of those headers because my server won't accept requests larger then 8k.
My solution thus far was to intercept all outgoing ajax request from my application.
I'm using jQuery Global Ajax Events, particularly ajaxSend to intercept all requests. I cannot use beforeSend because that is a local event.
I can't seem to access the request headers in the callback. I need to read all request's header and cut down the logs header if it's too large.

You want to use beforeSend to modify the request before it is being sent. This is all covered in the documentation you've linked to.
The global ajaxSend event will not help you tamper with the request. The closest thing to global you can get would be to is call ajaxSetup, passing a beforeSend option to be default for all subsequent ajax calls.
There appears to be no simple way of getting request headers from an XMLHttpRequest object. Since I assume you're setting your logging headers yourself, however, you might be able to hook into the setting of these headers, and store an accessible reference to them:
XMLHttpRequest.prototype.readableHeaders = {};
XMLHttpRequest.prototype.proxiedSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
XMLHttpRequest.prototype.setRequestHeader = function(header, value) {
this.proxiedSetRequestHeader(header, value);
this.readableHeaders[header] = value;
};
In this manner, you should be able to directly inspect the jqXHR.readableHeaders object for your specific logging header, in beforeSend, and call setRequestHeader once more, to truncate the string, if needed.
To retrieve the headers you need access to the underlying instance of XMLHttpRequest from jqXHR object. Use xhr() function to retrieve the instance.
$.ajaxSetup({
beforeSend: function (jqXHR, settings) {
console.log( settings.xhr().readableHeaders );
}
});

Related

Get custom header using javascript?

If I set a custom header using php on the server side like this:
header('customheader: yay');
How do I receive this on the client side using javascript?
You will need to send another request to retrieve the headers. It's often not an issue if the url is cached. In this case, I will recommend you to use fetch API for the task.
fetch('/whatever/url').then(response => console.log(response.headers.get('customheader')));
use $.ajax().done() event jqXHR parameter
jqXHR.done(function( data, textStatus, jqXHR ) {});
Then call getResponseHeader() on the jqXHR object to get a list of response headers

Modify XmlHttpRequest just inside one function of the code

I use a jQuery plugin named Redactor, which can send ajax requests (link to the code). My site has an ajax authentication using header. So, I need to set header of all ajax requests, sending via redactor.
How can I modify just this request of the website without modifying the source file?
P.S. I don't need to modify XmlHttpRequest globally. I want to modify it just for this chunk of code.
You can use ajaxSetup() ( https://api.jquery.com/jquery.ajaxsetup/ ). You can define default values for all ajax request in jQuery. So you can force the header to requests sent by Redactor.
See this question : How can I add a custom HTTP header to ajax request with js or jQuery?
If you want to add a header (or set of headers) to every request then
use the beforeSend hook with $.ajaxSetup():
$.ajaxSetup({
beforeSend: function(xhr) {
xhr.setRequestHeader('x-my-custom-header', 'some value');
}
});
// Sends your custom header
$.ajax({ url: 'foo/bar' });
// Sends both custom headers
$.ajax({ url: 'foo/bar', headers: { 'x-some-other-header': 'some value' } });

jQuery: how to make ajaxSend wait for another Ajax response before proceeding?

I'm using jQuery (v.3.0.0) and I need ajaxSend() to check if a value is present in localStorage, to add it in the outgoing request headers.
If the value is not present in localStorage, ajaxSend() should get this value with another Ajax request and then send the original request with the correct value in the headers.
This must be a global handler, that applies to all jQuery Ajax requests that are sent out.
Let's make a code example.
$(document).ajaxSend(function (ev, req, opts) {
// Before sending any jQuery Ajax request
var original = req;
if (localStorage.foo) {
// If value "foo" is available, add it to the headers
req.setRequestHeader('foo', localStorage.foo);
} else {
// Otherwise get it first, and add it to the headers
$.get({url: '/foo', global: false})
.done(function (data, textStatus, req) {
// "foo" is received and added to the original request headers
localStorage.foo = data;
original.setRequestHeader('foo', data);
// Now the original request is ready to be sent
});
}
});
When foo is not available, the problem with the code above is that obviously the original request is sent out before the value of foo is retrieved.
Is there any way to fix this and get it to work properly?
Thanks!!
So far, this is the best solution that I could find. It's not perfect, and it does not exactly answer the original question, but it's a good workaround and gets very close to what I was trying to achieve.
The main difference is that instead of making the original request wait, it cancels it, it gets the desired value, and then it creates a new request with the same settings as the original one.
$(document).ajaxSend(function (ev, req, opts) {
if (localStorage.foo) {
// If value "foo" is available, add it to the headers
req.setRequestHeader('foo', localStorage.foo);
} else {
// Otherwise cancel the original request, then get "foo",
// and create a new request with the same settings as the original one
req.abort();
$.get({url: '/foo', global: false})
.done(function (data, textStatus, req) {
// "foo" is received
localStorage.foo = data;
})
.then(function () {
$.ajax(opts);
});
}
});
It works perfectly. If someone finds out a better solution that allows to directly use the original request I'll be happy to edit this answer and improve it.
Thanks!
I think you need to use the beforeSend option of $.ajax, you can return false from there if the value is present in localStorage in order to stop the request.
This will mean you always have to use the low-level $.ajax method, perhaps you could make your own set of wrappers for $.get, $.post, $.getJSON etc.
I found a solution that does not need to abort the original request as in Pensierinmusica's answer. Instead the send method of the xhr object of the original AJAX call is overridden, and the original send with arguments can then be invoked later when e.g. another AJAX request completes. See this answer: https://stackoverflow.com/a/30263533

$.getJSON .always() method won't execute on HTTP error

I'm trying to retrieve some google calendar information using getJson. In some cases the calendars I'm trying to retrieve may or may not be available and I'll get either GET HTTP error 403 or 404, other times GET will be succesful. My problem is I need to execute some code even in the cases GET fails to receive the data. I thought that using the .always method would execute this code regardless but it turns out it won't execute when a 403 or 404 happens. I also tried specifically target this cases using .fail method with no success. Any idea?
Adding the code:
function AcquireGroupFeed(GroupDataBase) {
// For each group the calendar information is aquired and, if the events are
// relevant they are added to the feed.
// The group's calendar URL
var CalUrl = "http://www.google.com/calendar/feeds/" + GroupDataBase.calendarid +
"/public/full?alt=json-in-script&callback=?";
// Acquiring the data from Google.
$.getJSON(CalUrl, function(data) {PushToEventFeed(data, GroupDataBase);})
.always(function(){CheckAllGroupsAcquired();});
}
I recently learned that, by using the $.ajax call instead of .getJSON I can handle the error when I fail to retrieve the URL. The timeout setup should be defined for the error to be handled:
$.ajax({
url: URL,
dataType: 'json',
timeout: 3000,
success: function( data ) { successFunction();},
error: function( data ) { errorHandling(); }
});
With this, I was able to solve my problem.
You are in fact doing a JSONP request, since the domain where the page is hosted is different from the one in the AJAX request. JSONP does not function by using the normal XMLHTTPRequest interface (it uses script elements), and it does not support failure callbacks.
If you look under the error option for the $.ajax function, you will see this note:
This handler is not called for cross-domain script and cross-domain JSONP requests
The same applies to $.getJSON (since it is a wrapper for $.ajax).
If you need a failure callback, you will probably need to program it yourself, maybe based on a two-second timer, or something like that.

How to send data in request body with a GET when using jQuery $.ajax()

The service API I am consuming has a given GET method that requires the data be sent in the body of the request.
The data required in the body is a list of id's separated by hypen and could potentially be very large and thus it must be sent in the body otherwise it will likely foobar somewhere in the browsers/proxies/webservers etc chain. Note I don't have control over the service or API so please don't make suggestions to change it.
I am using the following jQuery code however observing the request/response in fiddler I can see that the "data" I am sending is ALWAYS converted and appended to the query string despite me setting the "processData" option to false...
$.ajax({
url: "htttp://api.com/entity/list($body)",
type: "GET",
data: "id1-id2-id3",
contentType: "text/plain",
dataType: "json",
processData: false, // avoid the data being parsed to query string params
success: onSuccess,
error: onError
});
Anyone know how I can force the "data" value to be sent in the body of the request?
In general, that's not how systems use GET requests. So, it will be hard to get your libraries to play along. In fact, the spec says that "If the request method is a case-sensitive match for GET or HEAD act as if data is null." So, I think you are out of luck unless the browser you are using doesn't respect that part of the spec.
You can probably setup an endpoint on your own server for a POST ajax request, then redirect that in your server code to a GET request with a body.
If you aren't absolutely tied to GET requests with the body being the data, you have two options.
POST with data: This is probably what you want. If you are passing data along, that probably means you are modifying some model or performing some action on the server. These types of actions are typically done with POST requests.
GET with query string data: You can convert your data to query string parameters and pass them along to the server that way.
url: 'somesite.com/models/thing?ids=1,2,3'
we all know generally that for sending the data according to the http standards we generally use POST request.
But if you really want to use Get for sending the data in your scenario
I would suggest you to use the query-string or query-parameters.
1.GET use of Query string as.
{{url}}admin/recordings/some_id
here the some_id is mendatory parameter to send and can be used and req.params.some_id at server side.
2.GET use of query string as{{url}}admin/recordings?durationExact=34&isFavourite=true
here the durationExact ,isFavourite is optional strings to send and can be used and req.query.durationExact and req.query.isFavourite at server side.
3.GET Sending arrays
{{url}}admin/recordings/sessions/?os["Windows","Linux","Macintosh"]
and you can access those array values at server side like this
let osValues = JSON.parse(req.query.os);
if(osValues.length > 0)
{
for (let i=0; i<osValues.length; i++)
{
console.log(osValues[i])
//do whatever you want to do here
}
}
Just in case somebody ist still coming along this question:
There is a body query object in any request. You do not need to parse it yourself.
E.g. if you want to send an accessToken from a client with GET, you could do it like this:
const request = require('superagent');
request.get(`http://localhost:3000/download?accessToken=${accessToken}`).end((err, res) => {
if (err) throw new Error(err);
console.log(res);
});
The server request object then looks like {request: { ... query: { accessToken: abcfed } ... } }
You know, I have a not so standard way around this. I typically use nextjs. I like to make things restful if at all possible. If I need to make a get request I instead use post and in the body I add a submethod parameter which is GET. At which point my server side handles it. I know it's still a post method technically but this makes the intention clear and I don't need to add any query parameters. Then the get method handles a get request using the data provided in the post method. Hopefully this helps. It's a bit of a side step around proper protocol but it does mean there's no crazy work around and the code on the server side can handle it without any problems. The first thing present in the server side is if(subMethod === "GET"){|DO WHATEVER YOU NEED|}

Categories

Resources