Best ajax questions in January 2011

Why does Internet Explorer not send HTTP post body on Ajax call after failure?

44 votes

We are able to reliably recreate the following scenario:

  1. Create a small HTML page that makes AJAX requests to a server (using HTTP POST)
  2. Disconnect from the network and reconnect
  3. Monitor the packets that IE generates after the failure

After a failed network connection, IE makes the next AJAX request but only sends the HTTP header (not the body) when doing the HTTP post. This causes all sorts of problems on the server as it is only a partial request. Google this issue with Bing and you'll find lots of people complaining about "random server errors" using AJAX or unexplained AJAX failures.

We know that IE (unlike most other browsers) always sends an HTTP POST as TWO TCP/IP packets. The header and body is sent separately. In the case directly after a failure, IE only sends the header.

So my question is - why does it behave this way? It seems wrong based on the HTTP spec and other browsers don't behave this way. Is it simply a bug? Surely this creates havoc in any serious AJAX based Web application.

Reference information:

There is a similar problem, triggered by HTTP keep-alive timeouts that are shorter than 1 minute and is documented here:

http://us.generation-nt.com/xmlhttprequest-post-sometimes-fails-when-server-using-keep-aliv-help-188813541.html

http://support.microsoft.com/default.aspx?kbid=831167

Here are the before and after failure packet captures:

Notice how the HTTP Header and Payload is sent http://img827.imageshack.us/i/beforee.png/

After a failure, notice how only the Header is sent. IE never sends the payload and the server eventually responds with a Timeout. http://img203.imageshack.us/i/retryt.png/

There does not seem to be a clear answer to this question, so I will provide my empirical data as a substitute and provide some ways to work around it. Maybe some MS insider will one day shed some light on this...

  1. If HTTP Keep-Alive is disabled on the server, this issue goes away. In other words, your HTTP 1.1 server server will respond to every Ajax request with a Connection: Close line in the response. This keeps IE happy but causes every Ajax request to open a new connection. This can have a significant performance impact, especially on high latency networks.

  2. The issue is triggered easily if Ajax requests are made in rapid succession. For example, we make Ajax requests every 100ms and then the network status changes, the error is easy to reproduce. Although most applications probably do not make such requests, you might well have a couple of server calls happening right after each other which could lead to this problem. Less chatty keeps IE happy.

  3. It happens even without NTLM authentication.

  4. It happens when your HTTP keep-alive timeout on the server is shorter than the default (which defaults to 60 seconds on Windows). Details provided in link in question.

  5. It does not happen with Chrome or Firefox. FF sends one packet so seems to avoid this issue altogether.

  6. It happens in IE 6, 7, 8. Could not reproduce with IE 9 beta.

In 2011 is it truly necessary to still degrade js?

16 votes

Serious question.

I tried most of the famous websites (including facebook) and I can say that tons of functionality doesn't degrade at all with js disabled. I've been always told that js should degrade gracefully, but does this still applies in these day and age?

ie6 support is being dropped by several sites, and most of the web2.0 relies heavily on js (especially ajax, I even found some sites that doesn't let you login without js enabled).

What are your thoughts about it?

EDIT:

I want to add that I for one develop webapps without js first and then enhancing them with it. The issue is that year after year js is more and more a part of the web. HTML5, canvas and heavy js apps are starting to rise. Will we ever reach the point where js will be compulsory in most of the websites? I talked about facebook because the site actually degrades and is usable without js but most of the functionalities and shortcuts are stripped to the poin that the site feels dull and old. There are also example where js is better than server side scripting, for instance the ordering of large tables is faster and less server intensive that a php implementation.

p.s. I don't know how to make this a community wiki, but I will, I'm just interested in your opinions.

In 2011 there are still several important types of users for whom you can't assume javascript will function properly:

  • search robots
  • browsers for visually impaired users
  • feature phones
  • corporate browsers, thin clients, etc still using IE6 or whatever
  • REST-based clients by fellow developers
  • your frontend usability testing tools
  • weird new browsers like my mom's Roku TV box

So I think it's still best to offer graceful degradation.

Implementing a live voting system

6 votes

I'm looking at implementing a live voting system on my website. The website provides a live stream, and I'd like to be able to prompt viewers to select an answer during a vote initiated by the caster. I can understand how to store the data in a mySQL database, and how to process the answers. However:

How would I initially start the vote on the client-side and display it? Should a script be running every few seconds on the page, checking another page to see if a question is available for the user?

Are there any existing examples of a real-time polling system such as what I'm looking at implementing?

You would have to query the server for a new question every few seconds.

The alternative is to hold the connection open until the server sends more data or it times out, which just reduces (but does not eliminate) the server hits. I think it is called "long polling". http://en.wikipedia.org/wiki/Push_technology

Ajax Validation Using jquery?

6 votes

I using jquery validation plugin.

In my form i need to check whether the nick name is already in use or not.

For that they are providing remote key to make ajax call. For me the ajax call is working correctly and returning true or false. But its allowing even if the returned value is false, which should not happen.

My validation code looks like,

$(function() {
    $("#myform").validate({
        rules: {
            fullName: {
                required: true,
                minlength: 5
            },
            nickName: {
                required: true,
                minlength: 4,
                alphaNumeric: true,
                remote: {
                    url: "NickNameChecker",
                    type: "post",
                    data: {
                        nickName: function() {
                        return $("#nickName").val();
                    }},
                    success: function(data) {
                        return data;
                    }
                }
            }
        },
        messages: {
            fullName: {
                required: "Please Enter Your Full Name.",
                minlength: "Full Name should have minimum 5 letters."
            },
            nickName: {
                required: true,
                minlength: "Nick Name should contain minimum 4 letters.",
                remote: "This nickname is already in use."
            }
        }
    });
});

Any suggestions would be appreciative!!!

Thanks!

Solution:

The solution is in my code only.

I just removed the success part and tried. Its working great!

(Expanded explanation from comment above):

The success option is not valid for jQuery validate's remote validation. You should be able to just specify a URL to access for validation that returns true or a falsy value/error message:

The serverside resource is called via $.ajax (XMLHttpRequest) and gets a key/value pair, corresponding to the name of the validated element and its value as a GET parameter. The response is evaluated as JSON and must be true for valid elements, and can be any false, undefined or null for invalid elements, using the default message; or a string

See the documentation for remote for more information on how to use the option. Your code would probably look something like this:

$(function() {
    $("#myform").validate({
        rules: {
            fullName: {
                required: true,
                minlength: 5
            },
            nickName: {
                required: true,
                minlength: 4,
                alphaNumeric: true,
                remote: {
                    url: "NickNameChecker",
                    type: "post",
                    data: {
                        nickName: function() {
                        return $("#nickName").val();
                    }
                }
            }
        },
        messages: {
            fullName: {
                required: "Please Enter Your Full Name.",
                minlength: "Full Name should have minimum 5 letters."
            },
            nickName: {
                required: true,
                minlength: "Nick Name should contain minimum 4 letters.",
                remote: "This nickname is already in use."
            }
        }
    });
});

How to design a multi-user ajax web application to be concurrently safe

6 votes

I have a web page that shows a large amount of data from the server. The communication is done via ajax.

Every time the user interacts and changes this data (Say user A renames something) it tells the server to do the action and the server returns the new changed data.

If user B accesses the page at the same time and creates a new data object it will again tell the server via ajax and the server will return with the new object for the user.

On A's page we have the data with a renamed object. And on B's page we have the data with a new object. On the server the data has both a renamed object and a new object.

What are my options for keeping the page in sync with the server when multiple users are using it concurrently?

Such options as locking the entire page or dumping the entire state to the user on every change are rather avoided.

If it helps, in this specific example the webpage calls a static webmethod that runs a stored procedure on the database. The stored procedure will return any data it has changed and no more. The static webmethod then forwards the return of the stored procedure to the client.

Bounty Edit:

How do you design a multi-user web application which uses Ajax to communicate with the server but avoids problems with concurrency?

I.e. concurrent access to functionality and to data on a database without any risk of data or state corruption

Overview:

  • Intro
  • Server architecture
  • Client architecture
  • Update case
  • Commit case
  • Conflict case
  • Performance & scalability

Hi Raynos,

I will not discuss any particular product here. What others mentioned is a good toolset to have a look at allready (maybe add node.js to that list).

From an architectureal viewpoint, you seem to have the same problem that can be seen in version control software. One user checks in a change to an object, another user wants to alter the same object in another way => conflict. You have to integrate users changes to objects while at the same time being able to deliver updates timely and efficently, detecting and resolving conflicts like the one above.

If I was in your shoes I would develop something like this:

1. Server-Side:

  • Determine a reasonable level at which you would define what I'd call "atomic artifacts" (the page? Objects on the page? Values inside objects?). This will depend on your webservers, database & caching hardware, # of user, # of objects, etc. Not an easy decision to make.

  • For each atomic artifact have:

    • an application-wide unique-id
    • an incrementing version-id
    • a locking mechanism for write-access (mutex maybe)
    • a small history or "changelog" inside a ringbuffer (shared memory works well for those). A single key-value pair might be OK too though less extendable. see http://en.wikipedia.org/wiki/Circular_buffer
  • A server or pseudo-server component that is able to deliver relevant changelogs to a connected user efficently. Observer-Pattern is your friend for this.

2. Client-Side:

  • A javascript client that is able to have a long-running HTTP-Connection to said server above, or uses lightweight polling.

  • A javascript artifact-updater component that refreshes the sites content when the connected javascript client notifies of changes in the watched artifacts-history. (again an observer pattern might be a good choice)

  • A javascript artifact-committer component that may request to change an atomic artifact, trying to acquire mutex lock. It will detect if the state of the artifact had been changed by another user just seconds before (latancy of javscript client and commit process factors in) by comparing known clientside artifact-id and current serverside artifact-id.

  • A javascript conflict-solver allowing for a human which-change-is-the-right decission. You may not want to just tell the user "Someone was faster than you. I deleted your change. Go cry.". Many options from rather technical diffs or more user-friendly solutions seem possible.

So how would it roll ...

Case 1: kind-of-squence-diagramm for updating:

  • Browser renders page
  • javascript "sees" artifacts which each having at least one value field, unique- and a version-id
  • javascript client gets started, requesting to "watch" the found artifacts history starting from their found versions (older changes are not interesting)
  • Server process notes the request and continously checks and/or sends the history
  • History entries may contain simple notifications "artifact x has changed, client pls request data" allowing the client to poll independently or full datasets "artifact x has changed to value foo"
  • javascript artifact-updater does what it can to fetch new values as soon as they become known to have updated. It executes new ajax requests or gets feeded by the javascript client.
  • The pages DOM-content is updated, the user is optionally notified. History-watching continues.

Case 2: Now for committing:

  • artifact-committer knows the disered new value from user input and sends a change-request to the server
  • serverside mutex is acquired
  • Server receives "Hey, I know artifact x's state from version 123, let me set it to value foo pls."
  • If the Serverside version of artifact x is equal (can not be less) than 123 the new value is accepted, a new version id of 124 generated.
  • The new state-information "updated to version 124" and optionaly new value foo are put at the beginning of the artifact x's ringbuffer (changelog/history)
  • serverside mutex is released
  • requesting artifact committer is happy to recive a commit-confirmation together with the new id.
  • meanwhile serverside server component keeps polling/pushing the ringbuffers to connected clients. All clients watching the buffer of artifact x will get the new state information and value within their usual latancy (See case 1.)

Case 3: for conflicts:

  • artifact committer knows disered new value from user input and sends a change-request to the server
  • in the meanwhile another user updated the same artifact successfully (see case 2.) but due to various latancies this is yet unknown to our other user.
  • So a serverside mutex is acquired (or waited on until the "faster" user committed his change)
  • Server receives "Hey, I know artifact x's state from version 123, let me set it to value foo."
  • On the Serverside the version of artifact x now is 124 allready. The requesting client can not know the value he would be overwriting.
  • Obviously the Server has to reject the change request (not counting in god-intervening overwrite priorities), releases the mutex and is kind enough to send back the new version-id and new value directly to the client.
  • confronted with a rejected commit request and a value the change-requesting user did not yet know, the javascript artifact committer refers to the conflict resolver which displays and explains the issue to the user.
  • The user, beeing presented with some options by the smart conflict-resolver JS, is allowed another attempt to change the value.
  • Once the user selected a value he deems right, the process starts over from case 2 (or case 3 if someone else was faster, again)

Some words on Perfomance & Scalability

HTTP Polling vs. HTTP "pushing"

  • Polling creates requests, one per second, 5 per second, whatever you regard as an acceptable latency. This can be rather cruel to your infrastructure if you do not configure your (Apache?) and (php?) well enough to be "lightweight" starters. It is desirable to optimize the polling request on the serverside so that it runs for far less time than the length of the polling interval. Splitting that runtime in half might well mean lowering your whole system load by up to 50%,
  • Pushing via HTTP (asuming webworkers are too far off to support them) will require you to have one apache/lighthttpd process available for each user all the time. The resident memory reserved for each of these processes and your systems total memory will be one very certain scaling limit that you will encounter. Reducing the memory footprint of the connection will be necessary, as well as limiting the amount continous CPU and I/O work done in each of these (you want lots of sleep/idle time)

backend scaling

  • Forget database and filesystem, you will need some sort of shared memory based backend for the frequent polling (if the client does not poll directly then each running server process will)
  • if you go for memcache you can scale better, but its still expensive
  • The mutex for commits has to work globaly even if you want to have multiple frontend servers to loadbalance.

frontend scaling

  • regardless if you are polling or receiving "pushes", try to get information for all watched artifacts in one step.

"creative" tweaks

  • If clients are polling and many users tend to watch the same artifacts, you could try to publish the history of those artifacts as a static file, allowing apache to cache it, nevertheless refreshing it on the serverside when artifacts change. This takes PHP/memcache out of the game some for requests. Lighthttpd is verry efficent at serving static files.
  • use a content delivery network like cotendo.com to push artifact history there. The push-latancy will be bigger but scalability's a dream
  • write a real server (not using HTTP) that users connect to using java or flash(?). You have to deal with serving many users in one server-thread. Cycling through open sockets, doing (or delegating) the work required. Can scale via forking processes or starting more servers. Mutexes have to remain globaly unique though.
  • Depending on load scenarious group your frontend- and backend-servers by artifact-id ranges. This will allow for better usage of persistent memory (no database has all the data) and makes it possible to scale the mutexing. Your javascript has to maintain connections to multiple servers at the same time though.

Well I hope this can be a start for your own ideas. I am sure there are plenty more possibilities. I am more than welcoming any criticism or enhancements to this post, wiki is enabled.

Christoph Strasen

Ajax heavy JS apps using excessive amounts of memory over time.

5 votes

I seem to have some pretty large memory leaks in an app that I am working on. The app itself is not very complex. Every 15 seconds, the page requests approx 40kb of JSON from the server, and draws a table on the page using it. It is cheaper to draw the table over because the data is usually always new. I am attaching a few events to the table, approx 5 per line, 30 lines in the table. I used jQuery's .html() method to put the new html into the container and overwrite the existing. I do this specifically so that jQuery's special cleanup functions go in and attempt to detach all events on the elements in the element that it is overwriting. I then also delete the large variables of html once they are sent to the DOM using delete my_var.

I have checked for circular references and attached events that are never cleared a few times, but never REALLY dug into it. I was wondering if someone could give me a few pointers on how to optimize a very heavy app like this. I just picked up "High Performance Javascript" by Nicholas Zakas, but didn't have much time to get into it yet.

To give an idea on how much memory this is using, after 4~ hours, it is using about 420,000k on chrome, and much more on Firefox or IE.

Thanks!

I'd suggest writing a test version of your script without events. DOM / JS circular references might be very hard to spot. By eliminating some variables from the equation, you might be able to narrow down your search a bit.

User interaction sometimes screws up jQuery ajax requests in UIWebView

4 votes

I'm building an iPhone app that displays a UIWebView pointing to a web application I've created.

The web application makes frequent web service calls for data items which are used to animate controls on a canvas. The calls for data use jQuery ajax, passing parameters via JSON and receiving an XML response.

I'm finding that while user interactions with the UIWebView are occurring, the javascript setTimeout method is blocked and doesn't seem to execute at all. Fair enough; there are ways around this.

But the major problem is that every now and then after user interactions (zooming, panning etc), the ajax web service calls will just fail all the time and I can't establish a reason why. Even if they are made repeatedly, for the next few minutes none of them will even get through to the web service. If you completely leave the UIWebView alone, they will never fail as long as the web service is up and connectivity is present.

Can anyone suggest why, and how to fix/work around this?

Quick update: according to the Safari mobile debugger, the 'response' object in the error function is undefined. (It works if, for example, I make the URL invalid. This can then be called from objective-c by [webView stringByEvaluatingJavascript:@"lastError"], but throws an exception for this 'touched the uiwebview' error):

    $.ajax({
    type: "POST",
    url: "WebService.asmx/GetValues",
    async: true,
    data: "{'pageVersionIndex': " + PageVersionIndex + " , 'timeStreamIndex': '" + TimeStream + "'}",
    contentType: "application/json; charset=utf-8",
    dataType: "xml",
    success: function (response) { UpdateControls(response); },
    error: function (response, status, errorthrown) {
        calling = false;
        lastError = response.statusText; //Throws exception
        connectionInterrupted = true;
        DataRoutine = window.setTimeout(DataService, dataFrequency); }
    });

I'm afraid you are toasted... in a way. In iOS Safari and in UIWebView respectively system processes have priority over browser and if there is a sudden demand for more CPU power or memory for native processes (like handling touch etc) it might happen that any running javascript will be stopped from executing to reduce the memory load or cpu usage. The worst part is that it won't throw any errors or anything... it just stops your code execution as if nothing happened.

Afraid that if it happens a lot in your app the only way would be to add some kind of timer that would listen if the request wasn't blocked if so - do it again until successful.

Ups and downs of iOS - they really like you to go native rather then web :)

hope it helps, Tom

HTML5 file upload feature detections in browser

4 votes

I am trying to upload the files using the HTML5 features. As per the investigation i have found that there are 3 different ways of uploading the files,

  1. By encoding file as multipart: This is done when there is support for file reader only.
  2. Send binary data using XMLHTTP2(AJAX) spec method: New method send(Blob/File) is able to send the binary data across the wire.
  3. FormData object: Using XMLHTTP(AJAX) send(FormData) method.

Now for cross browser issues and feature detections snippet like below is simple,

if(typeof FileReader == "undefined")

However i am not sure how to find out if send() method of the AJAX in current browser is supporting send(FormData) or send(Blob/File) method implementation. How to find it ? Is there is Object.property trick here ? Or something different ?

Thanks,

To handle binary data you will want to use WebSockets. This is part of the new HTML5 spec. There is a problem, though. As of mid-December, 2010, WebSockets were disabled in every major browser because of a cache-poisoning vulnerability.

Last I heard this was still being sorted out.

To upload the file before sending it via WebSockets you should use the FileReader API which is supported in the latest version of each browser (to the best of my knowledge).

To check if the FileReader is supported you should test like:

if (FileReader){
  // It's supported
}

You can also check for:

if (window.URL){
  //
}

for an alternative.

Is this the fastest way to parse my XML into JavaScript objects using jQuery?

4 votes

I have an XML file like this:

<content>
    <box>
        <var1>A1</var1>
        <var2>B1</var2>
        <var3>C1</var3>
        <var4>D1</var4>
    </box>
    <box>
        <var1>A2</var1>
        <var2>B2</var2>
        <var3>C2</var3>
        <var4>D2</var4>
    </box>
    <box>
        <var1>A3</var1>
        <var2>B3</var2>
        <var3>C3</var3>
        <var4>D3</var4>
    </box>
</content>

It has 500 box elements which I need to parse into JavaScript objects. I am using this code which works fine but I am a newbie and maybe I am missing something and would like to get suggestions if there is a better/faster way to do it:

var app = {
    //...
    box: [],

    init: function (file) {
        var that = this;

        $.ajax({
            type: "GET",
            url: file,
            dataType: "xml",
            success: function (xml) {
                $("box", xml).each(function (i) {
                    var e = $(this);
                    that.box[i] = new Box(i, {
                        var1: e.children("var1").text(),
                        var2: e.children("var2").text(),
                        var3: e.children("var3").text(),
                        var4: e.children("var4").text()
                    });
                });
            }
        });
    },
    //...
};

Thanks in advance.

Use JSON if at all possible. That way the browser will do the parsing for you and you won't have to do any post-processing.

JSON from the server

{"content":
  {"box": [
    {"var1": "A1",
     "var2": "B1",
     "var3": "C1",
     "var4": "D1"},
    {"var1": "A2",
     "var2": "B2",
     "var3": "C2",
     "var4": "D2"},
    {"var1": "A3",
     "var2": "B3",
     "var3": "C3",
     "var4": "D3"}]}}

Client JavaScript

var app = {
    //...
    box: [],

    init: function (file) {
        var that = this;

        $.ajax({
            type: "GET",
            url: file,
            dataType: "json",
            success: function(result) {
              that.box = $.map(result.content.box, function(box, i) {
                return new Box(i, box);
              });
            }
        });
    },
    //...
};

CSRF token for ajax

4 votes

I have a problem with forms submitted with ajax. I do my forms with Zend Framework. Some are real forms so I add a Hash element. Others are for small operations (like upvote and downvote here) so I do them with links.

My problem is that I need to use ajax especially for the small forms (the links). I see a lot of questions but nothing comprehensive enough to solve the problem. Is there a detailed description on how to get csrf token working smoothly when forms are submitted via ajax? preferably with Zend Framework but general PHP answers will help too.

You don't need a CSRF token. You case use the HTTP_X_REQUESTED_WITH method (see e.g. here).

jQuery with Microsoft - Tutorials/Resources?

4 votes

Can anyone suggest some resources (books/videos/tutorials) that focus on using jQuery with classic ASP and ASP.NET? Having used ASP.NET AJAX a while back I find things are quite a bit different now with Microsoft embracing jQuery and deprecating ASP.NET AJAX. Thank you.

Update

I have never been a fan of the AJAX implementation supported by Microsoft (ScriptManager, UpdatePanel, etc ..). Now with Microsoft seemingly abandoning these controls (i.e. ASP.NET AJAX Control Toolkit) and embracing jQuery I am looking for tutorials and/or articles that cover to implement AJAX within ASP.NET application using jQuery.

try the following:

Using jQuery with ASP .NET
Using jQuery with ASP.NET Part 2: Making Ajax Callbacks to the Server
(first part makes introduction to jQuery)

about books, I don't know any dedicated to using jQuery with ASP.NET, there is one eBook jQuery for ASP.NET Developers, but looking at Table of Contents, it is mostly about jQuery, only few pages described its using with ASP.NET, and I'm not sure it is worth to buy

How to regenerate jQuery Mobile style after Ajax request ?

4 votes

Hello,

I'd like to apply autogenerated jQuery Mobile style (classes jQuery Mobile applies on page loading) after additionnal content loading via Ajax.

I load some content via Ajax which is parsed and organised into a <ul>, but the style jQuery usually applies on page loading isn't applied on the Ajax loaded content.

Assuming your ul is a jquery-mobile "listview", try to refresh the entire list by using :

$('#yourlist').listview('refresh');

jQuery Mobile doucmentation http://jquerymobile.com/demos/1.0a2/#docs/forms/plugin-eventsmethods.html

jquery bind focus / blur events to AJAX loaded content

4 votes

I have this script which works fine to add / remove a class on blur / focus on text inputs and textareas - however I need to bind it to also work on content added after page load via AJAX:

 $(function() {
  $('input[type=text], textarea').addClass("idleField"); // reset all ##
  $('input[type=text], textarea').bind("focus", function(event){
      $(this).removeClass("idleField").addClass("focusField");
      if (this.value == this.defaultValue){ 
       this.value = '';
   }
   if(this.value != this.defaultValue){
       this.select();
      }
  }).bind("blur", function(event){
   $(this).removeClass("focusField").addClass("idleField");
      if ($.trim(this.value) == ''){
       this.value = (this.defaultValue ? this.defaultValue : '');
   }
  });

 });

this is not binding the events to new content - any ideas?

Instead of using .bind, use .live or .delegate, e.g.:

$('input[type=text], textarea').live("focus", function() {
    // stuff here will be applied to present and *future* elements
});

$("form").delegate("input[type=text], textarea", "focus", function() {
    // stuff here will be applied to present and *future* elements
});

How do I execute an authenticated AJAX request without resetting the tomcat's session timeout?

4 votes

I've got an existing Grails Web application that is in production and has a 30 minute session timeout. We are running Tomcat (tcServer).

When a user is authenticated and on certain pages I want to make some periodic polling ajax requests to the server that do not extend this 30 minute session timeout - so that our session timeout isn't thwarted.

The question is similar to this unanswered asp.net question, but none of the answers there will do and this in the Java/Tomcat realm.

How do I execute an authenticated AJAX request without resetting the tomcat's session timeout?

Is there some sort of filter or url-matching mechanism that I can use to exclude requests from extending the session timeout?

I'd go with a Grails filter that does something similar to what The-MeLLeR is proposing without the unnecessary loop through all sessions:

class AjaxTimeoutFilters {

   int sessionTimeout = 30 * 60 * 1000
   private static final String TIMEOUT_KEY = 'TIMEOUT_KEY'

   def filters = {
      all(controller:'*', action:'*') {
         before = {
            if (request.xhr) {
               Long lastAccess = session[TIMEOUT_KEY]
               if (lastAccess == null) {
                  // TODO
                  return false
               }
               if (System.currentTimeMillis() - lastAccess > sessionTimeout) {
                  session.invalidate()
                  // TODO - render response to trigger client redirect
                  return false
               }
            }
            else {
               session[TIMEOUT_KEY] = System.currentTimeMillis()
            }

            true
         }
      }
   }
}

The session timeout should be dependency-injected or otherwise kept in sync with the value in web.xml.

There are two remaining issues. One is the case where there's an Ajax request but no previous non-Ajax request (lastAccess == null). The other is how to redirect the browser to a login page or wherever you need to go when there's an Ajax request after 30 minutes of no non-Ajax activity. You'd have to render JSON or some other response that the client would check to know that it's been timed out and do a client-side redirect.