Handling 304 Not Modified Responses in DataTables with ETag

Handling 304 Not Modified Responses in DataTables with ETag

abanetabanet Posts: 9Questions: 2Answers: 0

Hi!

I'm currently implementing ETag handling in my application to manage the cache and ensure that the client only receives new data if it has been modified. I've set up the server to return a 304 Not Modified status along with the ETag when there is no new data to send.

However, I am encountering an issue where DataTables does not seem to handle the 304 Not Modified status correctly. It seems to expect always data in the response and runs into trouble when the response is empty or not as expected due to the 304 status.

Is there a built-in way for DataTables to correctly interpret and handle a 304 Not Modified response, allowing it to continue displaying the currently cached data without any additional actions or errors?

Thank you for your assistance.

Best regards,
Alberto Banet

This question has an accepted answers - jump to answer

Answers

  • allanallan Posts: 60,903Questions: 1Answers: 9,927 Site admin

    Hi Alberto,

    I'd think that if the server is returning 304, then it would be up to the browser to pass the data back from its cache and jQuery would pass that to us.

    Can you give me a link to your page so I can dig into the trace please?

    Thanks,
    Allan

  • abanetabanet Posts: 9Questions: 2Answers: 0

    Thanks for your quick response Allan. Unfortunately access to my website is not possible from outside the company.
    I am loading data from the Ajax option of datatables itself:

         var tablaEspacios = $('#tablaEspacios').DataTable({
        ...
          ajax: { ...
                  dataSrc:
                        function(response) {
                            $.each(response, function (index, value) {
                                var name = value.categoriaCv.descripcion;
                                collapsedGroups[name] = !value.categoriaCv.expandido; 
                            });
                            return response;
                        },
                   ...     
    

    I don't know if this can be a problem. In any case, what you have told me helps me try another approach to the problem. Thank you so much!!

  • allanallan Posts: 60,903Questions: 1Answers: 9,927 Site admin

    response is an empty string when the server returns 304? If so, I'm not sure where DataTables would get the data from.

    Could you try adding this at the start of your dataSrc function please?

    console.log( 'status', DataTable.settings[0].jqXHR.status );
    console.log( 'responseText', DataTable.settings[0].jqXHR.responseText );
    

    And let me know what that shows on the console?

    Allan

  • abanetabanet Posts: 9Questions: 2Answers: 0

    Hi Allan, the failure occurs before between the ajax call (the code in beforeSend is executed and mounts a valid ETag), immediately after it a crash occurs in jquery.dataTables.min.js: "TypeError: n is undefined". First call (after removing cache) the behavior is correct.

    I include all the code for the ajax call I am trying:

    ajax: {
        type: "GET",
        url: window.location.origin + '/es.pacv.api/listaEspaciosInicio',
         dataType: 'json',
         beforeSend: function(jqXHR) {
              var etag = localStorage.getItem('etag');
              if (etag) {
                      jqXHR.setRequestHeader('If-None-Match', etag);
               }
               console.log("BeforeSend: montando header if-none-match con etag: " + etag);
          },
    
          complete: function(jqXHR) {
                console.log("Entrando en complete");
                var etag = jqXHR.getResponseHeader('ETag');
                 if (etag) {
                      localStorage.setItem('etag', etag);
                       console.log("Complete: almacenado etag: " + etag);
                   }
                  if (jqXHR.status === 304) {
                       var cachedData = localStorage.getItem('cachedData');
                        if (cachedData) {
                            console.log("procesando datos localStorate" + cachedData);
                         }
                    }
            },
    
         dataSrc:
               function(response) {
                    console.log( 'status', DataTable.settings[0].jqXHR.status );
                    console.log( 'responseText', DataTable.settings[0].jqXHR.responseText );
                    $.each(response, function (index, value) {
                        var name = value.categoriaCv.descripcion;
                         collapsedGroups[name] = !value.categoriaCv.expandido; 
                       });
                      localStorage.setItem('cachedData', response);
                      return response;
                },
           },
    
  • allanallan Posts: 60,903Questions: 1Answers: 9,927 Site admin

    Could you use the non-min version of DataTables and let me know the error message and line number of the error?

    Thanks,
    Allan

  • abanetabanet Posts: 9Questions: 2Answers: 0

    Great idea! :smile:

    Error is at line 3929 var error = json.error || json.sError;
    TypeError: json is undefined.
    data: "Error: variable 'data' has been optimized out"

    I have verified that the object I cache is a well-formed json, but it may not be the one expected and that is where the problems come from...

  • allanallan Posts: 60,903Questions: 1Answers: 9,927 Site admin
    Answer ✓

    Thanks. This is the line in the DataTables source. The callback function is assigned to the success action from jQuery, so it means that undefined is what is being returned by jQuery's Ajax call to DataTables.

    If you put a breakpoint on that line of code and inspect the oSettings.jqXHR property, what are its status and responseText values?

    DataTables expects a valid JSON response from the server, although there is an exception a few lines above for 204 (No Content) and a null JSON return. I wonder if it should check for 304 there as well - but then the responsibility for filling in the data is 100% on the author.

    I'm tempted to suggest that you use ajax as a function and side step the DataTables / jQuery Ajax stuff. Doing it that way you get a callback function that you just give the data the table should render - it doesn't matter if it is Ajax sourced or from somewhere else.

    Allan

  • abanetabanet Posts: 9Questions: 2Answers: 0

    Hi Allan, yes, I finally did it that way without a problem. It is true that it is not Datatables' task to know if the data comes from a 200 or a 304 whenever it comes. And in this way there is also more possibility of managing cases according to my needs on each page.
    Thank you very much for your time, your suggestions have been really useful to me.
    Here I put the final code in case it could help someone.

    $.ajax({
            url: window.location.origin + '/es.pacv.api/listaEspaciosInicio',
            method: 'GET',
            dataType: 'json',
            headers: {
                'If-None-Match': localStorage.getItem('etag') || ''  
            },
            statusCode: {
                304: function () {
                    var datosCache = JSON.parse(localStorage.getItem('respuestaAPI'));
                    if (datosCache) {
                        tablaEspacios.clear().rows.add(datosCache).draw();
                    }
                }
            },
        }).done(function (data, textStatus, xhr) {
            if (xhr.status === 200) {
                var nuevoEtag = xhr.getResponseHeader('ETag'); 
                if (nuevoEtag) {
                    localStorage.setItem('etag', nuevoEtag); 
                }
                localStorage.setItem('respuestaAPI', JSON.stringify(data));
                if (data !== null || data.length >0) {
                    tablaEspacios.clear().rows.add(data).draw();
                }
            }
        }).always(function () {
            $(".spinner").fadeOut("slow");
        });
    
  • allanallan Posts: 60,903Questions: 1Answers: 9,927 Site admin

    Thanks for sharing your solution! Great to hear you got it working as needed!

    Allan

Sign In or Register to comment.