jQuery AJAX produce 304 respuestas cuando no debería
http-status-code-304 (3)
Esto realmente me tiene rascarme la cabeza. Es decir, porque solo ocurre en IE, no en Firefox, y tenía la impresión de que jQuery era efectivamente neutral para el navegador. He estado trabajando duro en esto durante las últimas horas y he clavado, al menos, lo que está sucediendo.
Este jqGrid:
$("#DocumentListByPartRecordsGrid").jqGrid(
{
datatype: ''local'',
colNames: [''<b>Id</b>'', ''<b>Document Name</b>'', ''<b>Document Type</b>'', ''<b>Effective Date</b>'', ''<b>Expiration Date</b>'', ''<b>Delete</b>''],
colModel: [
{ name: ''ASSOCIATION_ID'', Index: ''ASSOCIATION_ID'', resizable: true, align: ''left'', hidden: true, sortable: false },
{ name: ''FILE_NAME'', Index: ''FILE_NAME'', resizable: true, align: ''left'', sortable: false, width:''20%'' },
{ name: ''DOCUMENT_TYPE'', Index: ''DOCUMENT_TYPE'', resizable: true, align: ''left'', sortable: false, width:''20%'' },
{ name: ''EFFECTIVE_DATE'', Index: ''EFFECTIVE_DATE'', resizable: true, align: ''left'', sortable: false, width:''20%'' },
{ name: ''EXPIRATION_DATE'', Index: ''EXPIRATION_DATE'', resizable: true, align: ''left'', sortable: false, width:''20%'' },
{ name: ''Delete'', Index: ''Delete'',resizable: true, align: ''center'', sortable: false, width:''20%'' },
],
rowNum: 15,
rowList: [15, 50, 100],
imgpath: ''/Drm/Content/jqGrid/steel/images'',
viewrecords: true,
height: 162,
loadui: ''block'',
forceFit: true
});
Cumplido por esta función:
var mydata = '''';
<% if(!string.IsNullOrEmpty(Model.PCAssociatedDocuments)) { %>
var mydata = <%= Model.PCAssociatedDocuments %>;
<% } %>
for (var i = 0; i <= mydata.length; i++){
jQuery("#DocumentListByPartRecordsGrid").addRowData(i, mydata[i], "last");
}
Que se rellena limpiamente desde el modelo. Este no es el problema. El problema surge cuando se usa la funcionalidad de eliminación, que se formatea de nuevo en el controlador de la siguiente manera:
<a class=''deleteAttachment'' style=''cursor: pointer;'' href=''#'' onclick=''javascript:PCDocumentDelete(" + s.AssociationId.ToString() + ", " + pcId + ");''>Delete</a>
y llama a esta función
function PCDocumentDelete(id, pcid) {
if (confirm("Are you sure you want to delete this document?")) {
$.blockUI({
message: "Working...",
css: {
background: ''#e7f2f7'',
padding: 10
}
});
$.ajax(
{
url: ''/DRM/Pc/DeleteAssociation?associationId='' + id + ''&pcid='' + pcid,
async: true,
dataType: "json",
success: function(result) {
if (result.Success == true) {
//Reload grid
$.ajax({ async: false });
$("#DocumentListByPartRecordsGrid").setGridParam({ url: "/Drm/Pc/DeAssociatePartRecordsWithDocument?pcid=" + pcid, datatype: ''json'', myType: ''GET'', page: 1 });
$("#DocumentListByPartRecordsGrid").trigger("reloadGrid");
$.unblockUI();
$.showGlobalMessage(''Specified document has been successfully disassociated from this part record.'');
}
else {
$.unblockUI();
$.showGlobalMessage(''An error occurred deleting the attachment.'');
}
},
error: function(res, stat) {
alert(res.toString());
alert(stat.toString());
}
});
return false;
}
else {
return false;
}
}
(showGlobalMessage es una función interna que crea un bloqueUI con un formato particular)
El ajax vuelve a llamar a un método en el controlador, pero el problema surge antes de que lleguemos tan lejos, así que a menos que alguien piense que es importante, no voy a publicar ese código. Lo que sucede es que, a menudo por razones inexplicables, la primera ráfaga de ajax que llama a PC / DeleteAssociation vuelve con una respuesta 304 (no modificada). Sé que eso sucede cuando no se ha cambiado nada que deba actualizarse. Pero esto no es un acierto, debe tratarse como una publicación, y tuve la impresión de que jquery.ajax fue diseñado para, a menos que se indique lo contrario, no generar 304 respuestas. Obviamente me estoy perdiendo algo aquí y lo he estado mirando demasiado tiempo para atraparlo yo mismo. ¿Alguien ve lo que me perdí? Gracias.
- Siempre use POST para las llamadas a métodos que modifican el estado, no GET. Esto debería ser suficiente en este caso para evitar que IE almacene en caché la solicitud.
- IE almacena de forma agresiva las solicitudes de ajax (consulte http://www.dashbay.com/2011/05/internet-explorer-caches-ajax/ y https://blog.httpwatch.com/2009/08/07/ajax-caching-two-important-facts/ ). Para evitar esto, puedes:
- Agregue un parámetro
($.ajaxSetup({ cache: false });
caché($.ajaxSetup({ cache: false });
hace automáticamente. - Siempre use las solicitudes POST (probablemente no sea apropiado en la mayoría de los casos).
- Active los encabezados de caché para el lado del servidor de solicitudes AJAX. El primer enlace muestra cómo hacer esto usando groovy. Métodos similares deben aplicarse a cualquier marco.
- Agregue un parámetro
¡El caché es la solución!
En mi caso, la aplicación utilizó una única llamada de servicio con un encabezado personalizado como proxy para vincular el navegador con la parte privada del servidor (todas las llamadas fueron a la misma url, pero usaron un encabezado personalizado para indicar al servicio de proxy qué servicio pásalo a). Todo funcionó bien en Chrome y FF, pero IE siguió devolviendo datos desde la primera llamada realizada en la página. La opción cache = false en jQuery.ajax fue la solución, ya que IE solo observó la misma url que se llamaba, ni siquiera se molestó en ver si se usaban encabezados personalizados, o si se estaban pasando datos diferentes en el cuerpo, y simplemente dijo "oh, yo conozco a este, aquí .." y devolví la respuesta de la primera llamada. Con la técnica de eliminación de caché, la url se ve diferente a IE por lo que la envió.
No puedo verlo, especificando la solicitud ajax como POST. Así que básicamente añadir:
$.ajax({ type: ''POST'' });
y si eso todavía falla (debido a algunas rarezas de AJAX en el navegador), podría intentar configurar la cache: false
:
$.ajax({ type: ''POST'', cache: false });
Por cierto, todo caché: falso, está agregando algunas cosas aleatorias a la URL de solicitud.
EDIT1:
Con respecto a
... y tuve la impresión de que jquery.ajax fue diseñado para, a menos que se indique lo contrario, no generar 304 respuestas
jQuery no está generando ninguna respuesta aquí. Y el encabezado 304 es solo un encabezado HTTP. Las solicitudes HTTP AJAX son solicitudes HTTP normales y pueden devolver cualquier encabezado válido. Si el servidor responde con 304, el objeto XHR simplemente servirá la respuesta almacenada en caché local desde el servidor. Sin embargo, es completamente transparente para el usuario.
EDIT2:
Se eliminó el consejo sobre cómo prevenir el almacenamiento en caché. Me parece un vudú.
EDIT3:
Agregué ese bit de nuevo porque aparentemente era necesario. Mirando alrededor de la web, IE parece estar almacenando ilegalmente en la memoria caché AJAX POST en cierta medida.