2

I wanted to add a csrf token to all request bodies for ajax requests. i found the following post useful: jQuery add CSRF token to all $.post() requests' data

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
    options.data = $.param($.extend(originalOptions.data, { c: csrf }));
});

For some reason, this ovewrites the request body. i do not understand why. i can see when i serialize the request body its all there, but when it submits the body only contains the c field. It may be helpful to note that i am creating the form data using jQuery's serialize() method.

Community
  • 1
  • 1
r3wt
  • 4,642
  • 2
  • 33
  • 55
  • probably because `originalOptions.data` is a string when using .serialize(). If you instead used an object it would work. You could also use .serializeArray(), but you'd have to modify the prefilter to add the property in such a way that it matches the output from serializeArray. – Kevin B Nov 30 '15 at 20:38
  • if data is provided inconsistently, how can such a function expect to work – r3wt Nov 30 '15 at 20:40
  • 1
    Test if it is a string, if it is, convert it back to an object, add your parameter, and then re-stringify it. good luck with JSON or XML post bodies though. – Kevin B Nov 30 '15 at 20:41

1 Answers1

2

The code you found isn't working because it was built specifically for handling data that was passed in as an object rather than a param string.

There is however a much easier way of accomplishing this goal that won't be affected by how the data is passed in:

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
    if (options.processData && options.contentType === 'application/x-www-form-urlencoded; charset=UTF-8') {
        options.data = (options.data ? options.data + '&' : '') + $.param({ c: csrf });
    }
});

So instead of modifying the original object and adding a value, or converting the param string back to an object just to re-parse it, we param the new value we want to send and append it to the param string, only if processData is true and the contentType is set to default (to avoid mangling other content types.)

Kevin B
  • 94,570
  • 16
  • 163
  • 180
  • instead of doing that i just wrote a jquery function to serialize the form into an object instead of a string. why serialize it into a string if ajaxPrecheck is just going to unserialize it. bad practice. – r3wt Nov 30 '15 at 22:12
  • Yup. bad practice indeed. Note that you could also have swapped over to serializeArray, and had the prefilter differentiate between a serializeArray structure and a normal object structure, rather than introducing a serializeObject method. – Kevin B Nov 30 '15 at 22:13
  • if you feel like it, maybe add that to your answer. i'm always open to a better approach. – r3wt Nov 30 '15 at 22:24
  • I would, but, i don't remember the structure returned from serializeArray, haven't used it in years. – Kevin B Nov 30 '15 at 22:26
  • `[{ name: 'foo', value: 1} ,]` ie, each form input is an object of with properties called "name" and "value" – r3wt Nov 30 '15 at 22:29
  • note.... i'm not entirely confident on the usage of `options` vs `originalOptions`. I'd lean on the side of modifying `options` and not touching `originalOptions`, but that's probably irrelevant to this question. Your extend currently modifies what is in `originalOptions.data`. I've fixed that in my second snippet. – Kevin B Nov 30 '15 at 22:37
  • Ah... maybe that's because by the time it gets to the prefilter, it's already been paramed... – Kevin B Nov 30 '15 at 22:44
  • That is indeed the case, updated code to fix. Note that technically we're still serializing it to a string twice, always will be if we're using ajaxPrefilter. Only way to avoid that would be to make your own custom ajax method that wraps the jQuery one. – Kevin B Nov 30 '15 at 22:50
  • 1
    wait... we're way over complicating this. @r3wt – Kevin B Nov 30 '15 at 22:54