Safari บน iOS 6 กำลังแคชผลลัพธ์ $ .ajax หรือไม่


1072

ตั้งแต่การอัปเกรดเป็น iOS 6 เราเห็นว่ามุมมองทางเว็บของ Safari มีอิสระในการ$.ajaxโทรแคช นี่คือบริบทของแอปพลิเคชัน PhoneGap ดังนั้นจึงใช้ Safari WebView การ$.ajaxโทรของเราเป็นPOSTวิธีการและเราได้ตั้งค่าแคชเป็นเท็จ{cache:false}แต่ยังคงเกิดขึ้นอยู่ เราพยายามเพิ่ม a TimeStampไปยังส่วนหัวด้วยตนเองแต่มันก็ไม่ได้ช่วย

เราได้ทำการวิจัยเพิ่มเติมและพบว่า Safari กำลังส่งคืนผลลัพธ์แคชสำหรับบริการบนเว็บที่มีลายเซ็นฟังก์ชั่นที่เป็นแบบคงที่เท่านั้นและไม่เปลี่ยนแปลงจากการโทรถึงการโทร ตัวอย่างเช่นลองนึกภาพฟังก์ชั่นที่เรียกว่า:

getNewRecordID(intRecordType)

ฟังก์ชั่นนี้ได้รับพารามิเตอร์อินพุตเดียวกันซ้ำแล้วซ้ำอีก แต่ข้อมูลที่ส่งคืนควรแตกต่างกันทุกครั้ง

ต้องอยู่ในความรีบร้อนของ Apple เพื่อให้ iOS 6 zip พร้อมอย่างน่าประทับใจพวกเขามีความสุขกับการตั้งค่าแคช มีคนอื่นเห็นพฤติกรรมนี้ใน iOS 6 หรือไม่? ถ้าเป็นเช่นนั้นสิ่งที่ทำให้มันคืออะไร?


วิธีแก้ปัญหาที่เราพบคือการแก้ไขลายเซ็นของฟังก์ชันให้เป็นดังนี้:

getNewRecordID(intRecordType, strTimestamp)

จากนั้นส่งผ่านTimeStampพารามิเตอร์เสมอและทิ้งค่านั้นในฝั่งเซิร์ฟเวอร์ วิธีนี้สามารถแก้ไขปัญหาได้ ฉันหวังว่านี่จะช่วยวิญญาณที่น่าสงสารคนอื่นที่ใช้เวลา 15 ชั่วโมงในเรื่องนี้เหมือนฉัน!


190
นี่เป็นเรื่องที่น่าตกใจอย่างยิ่ง นอกจากนี้เรายังใช้เวลาสองสามชั่วโมงในการพยายามหาสิ่งที่หยุดทำงาน การเข้าสู่ระบบ AJAX ของเราที่ทำ POST (และมีส่วนหัวเพื่อป้องกันการแคชด้วย) กำลังถูกแคชโดย Safari ดังนั้นมันจึงส่งคืน JSON เดียวกับที่ใช้ครั้งล่าสุดโดยไม่ต้องลองเซิร์ฟเวอร์ ... ไม่น่าเชื่อ! เราจะต้องแฮ็กแก้ไข แต่คุณไม่ควรแคช POST มันบ้า
Kieran

16
โพสต์โซลูชันของคุณเป็นคำตอบแทนที่จะอัปเดตคำถาม
ChrisF

50
คำขอ POST นั้นไม่ใช่ idempotent ซึ่งหมายความว่าไม่ควรถูกแคชเว้นแต่ว่าการตอบสนองจะแนะนำเฉพาะการทำเช่นนั้นผ่านทางส่วนหัวการตอบสนอง
James M. Greene

6
แอปเปิ้ลที่จะได้รับการแก้ไขปัญหานี้ให้ยื่นข้อผิดพลาดที่bugreport.apple.com ฉันทำแบบเดียวกัน
Mathias Bynens

11
Mark Nottingham (ประธานคณะทำงาน IETF HTTPbis) เขียนโพสต์บล็อกที่น่าสนใจเกี่ยวกับเรื่องนี้ในวันนี้: mnot.net/blog/2012/09/24/caching_POST
Benjamin Brizzi

คำตอบ:


447

หลังจากการตรวจสอบเล็กน้อยปรากฎว่า Safari บน iOS6 จะแคช POST ที่ไม่มีส่วนหัวการควบคุมแคชหรือแม้แต่ "การควบคุมแคช: max-age = 0"

วิธีเดียวที่ฉันค้นพบในการป้องกันการแคชนี้เกิดขึ้นในระดับโลกแทนที่จะต้องแฮ็กข้อความแบบสุ่มลงในการเรียกใช้บริการเมื่อสิ้นสุดการโทรคือตั้ง "Cache-Control: no-cache"

ดังนั้น:

  • ไม่มีการควบคุมแคชหรือส่วนหัวที่หมดอายุ = iOS6 Safari จะแคช
  • Cache-Control max-age = 0 และ Expires ทันที = iOS6 Safari จะแคช
  • การควบคุมแคช: no-cache = iOS6 Safari จะไม่แคช

ฉันสงสัยว่า Apple กำลังใช้ประโยชน์จากสิ่งนี้จากข้อมูลจำเพาะ HTTP ในหัวข้อ 9.5 เกี่ยวกับ POST:

การตอบสนองต่อวิธีนี้ไม่สามารถแคชได้เว้นแต่ว่าการตอบกลับจะรวมถึงการควบคุมแคชหรือฟิลด์หมดอายุของส่วนหัวที่เหมาะสม อย่างไรก็ตามการตอบสนอง 303 (ดูอื่น ๆ ) สามารถนำมาใช้เพื่อกำหนดตัวแทนผู้ใช้เพื่อดึงทรัพยากรที่แคชได้

ดังนั้นในทางทฤษฎีคุณสามารถแคชการตอบสนอง POST ... ใครจะรู้ แต่ไม่มีผู้ผลิตเบราว์เซอร์คนอื่น ๆ ที่เคยคิดว่ามันจะเป็นความคิดที่ดีจนถึงปัจจุบัน แต่นั่นไม่ได้บัญชีสำหรับการแคชเมื่อไม่มีการตั้งค่าส่วนหัวการควบคุมแคชหรือหมดอายุเฉพาะเมื่อมีบางชุด ดังนั้นมันจะต้องเป็นข้อบกพร่อง

ด้านล่างคือสิ่งที่ฉันใช้ในบิตขวาของการกำหนดค่า Apache ของฉันเพื่อกำหนดเป้าหมาย API ทั้งหมดของฉันเพราะเมื่อมันเกิดขึ้นฉันไม่ต้องการแคชอะไรเลยแม้แต่จะได้รับก็ตาม สิ่งที่ฉันไม่รู้คือวิธีตั้งค่านี้เพียงโพสต์

Header set Cache-Control "no-cache"

อัปเดต: เพิ่งสังเกตเห็นว่าฉันไม่ได้ชี้ให้เห็นว่ามันเป็นเพียงเมื่อ POST เหมือนกันดังนั้นให้เปลี่ยนข้อมูล POST หรือ URL ใด ๆ ก็ได้และคุณก็สบายดี ดังนั้นคุณสามารถกล่าวถึงที่อื่นเพียงเพิ่มข้อมูลสุ่มลงใน URL หรือข้อมูล POST เล็กน้อย

อัปเดต: คุณสามารถ จำกัด "ไม่แคช" เพียงแค่โพสต์ถ้าคุณต้องการเช่นนี้ใน Apache:

SetEnvIf Request_Method "POST" IS_POST
Header set Cache-Control "no-cache" env=IS_POST

7
ฉันเห็นว่า Apple กำลังทำอะไรอยู่ แต่เราเห็นการตอบกลับที่แคชกับคำขอ POST แม้ว่าการตอบกลับของเราจะไม่รวมถึงการควบคุมแคชหรือส่วนหัวที่หมดอายุ อินสแตนซ์นี้เป็น iOS6 ไม่ควรแคชและส่งทุกคำขอ สิ่งนี้ไม่ได้เกิดขึ้น
Kango_V

138
ส่วนของข้อมูลจำเพาะ HTTP ที่คุณยกมาไม่ได้แสดงให้เห็นถึงพฤติกรรมการแคชของ iOS 6 พฤติกรรมเริ่มต้นไม่ควรแคชการตอบสนอง POST (เช่นเมื่อไม่ได้กำหนดส่วนหัว "การควบคุมแคช") พฤติกรรมละเมิดข้อกำหนดและควรได้รับการพิจารณาข้อบกพร่อง ทุกคนที่สร้างบริการเว็บ xml / json api ควรตกแต่งการตอบสนอง POST ด้วย "การควบคุมแคช: ไม่มีแคช" เพื่อแก้ไขปัญหานี้
David H

39
คำขอ POST นั้นไม่ใช่ idempotent ซึ่งหมายความว่าไม่ควรถูกแคชเว้นแต่ว่าการตอบสนองจะแนะนำเฉพาะการทำเช่นนั้นผ่านทางส่วนหัวการตอบสนอง
James M. Greene

4
อย่างที่เดวิดพูดมันเป็นการละเมิดประโยคที่คุณยกมาอย่างชัดเจน หากไม่มี "การควบคุมแคชหรือฟิลด์ส่วนหัวหมดอายุ" จะไม่รวมส่วนหัวดังกล่าวที่เหมาะสม แต่การสอบสวนของคุณเองก็แสดงว่าแคชในสถานการณ์นั้น โปรดแก้ไขคำตอบของคุณ
Matthew Flaschen

3
ไม่มีใครรู้ว่าผลลัพธ์จะถูกเก็บไว้บนอุปกรณ์นานแค่ไหน? ฉันได้ลองฆ่าซาฟารีแล้วรีสตาร์ทโทรศัพท์ แต่ก็ยังเก็บไว้ได้ ฉันรู้ว่าใช้งานได้กับการล้างแคชเบราว์เซอร์ แต่ฉันสงสัยว่าจะใช้เวลานานเท่าใดสำหรับผู้ใช้ที่เคยมีปัญหาก่อนที่มันจะหายไป ไม่ใช่ทุกคนที่จะคิดถึงการล้างแคชของตน ...
Daniel Hallqvist

146

ฉันหวังว่าสิ่งนี้สามารถนำไปใช้กับนักพัฒนาซอฟต์แวร์รายอื่นที่ต่อสู้กับกำแพงของกำแพงแห่งนี้ ฉันพบว่าสิ่งต่อไปนี้ป้องกัน Safari บน iOS 6 จากการแคชการตอบสนอง POST:

  • เพิ่ม [ควบคุมแคช: ไม่มีแคช] ในส่วนหัวคำขอ
  • การเพิ่มพารามิเตอร์ URL ตัวแปรเช่นเวลาปัจจุบัน
  • เพิ่ม [pragma: no-cache] ในส่วนหัวการตอบกลับ
  • การเพิ่ม [การควบคุมแคช: ไม่มีแคช] ในส่วนหัวการตอบสนอง

โซลูชันของฉันมีดังต่อไปนี้ใน Javascript ของฉัน (คำขอ AJAX ทั้งหมดของฉันคือ POST)

$.ajaxSetup({
    type: 'POST',
    headers: { "cache-control": "no-cache" }
});

ฉันยังเพิ่มส่วนหัว [pragma: no-cache] ในการตอบกลับของเซิร์ฟเวอร์จำนวนมาก

หากคุณใช้วิธีแก้ไขปัญหาข้างต้นโปรดทราบว่าการโทร $ .ajax () ใด ๆ ที่คุณตั้งไว้เป็น global: false จะไม่ใช้การตั้งค่าที่ระบุไว้ใน $ .ajaxSetup () ดังนั้นคุณจะต้องเพิ่มส่วนหัวอีกครั้ง


4
นี่คือทางออกที่ถูกต้องของข้อผิดพลาด ข้อบกพร่องคือ iOS 6 จะให้บริการคำขอ POST จากแคชมันแทนที่จะส่งไปยังเซิร์ฟเวอร์ ข้อผิดพลาดไม่ใช่ว่ามันแคชตอบสนองจากการร้องขอ POST (ซึ่งได้รับอนุญาต) หากคุณยังต้องการการตอบสนองต่อคำขอ POST ที่ดึงมาจากแคชสำหรับคำขอ GET ที่ตามมาไปยัง URI นั้นให้ใช้โซลูชันนี้
Nicholas Shanks

2
สิ่งนี้ใช้ได้สำหรับฉัน แต่ฉันไม่เข้าใจวิธีการ ฉันได้ระบุแคชแล้ว: false ใน ajaxSetup ของฉันและดูที่ส่วนหัวของคำขอซึ่งทำให้เดือดไปที่ Cache-Control: no-cache และ Pragma: no-cache - แต่มันจะยังคงแคชบน iPad จากนั้นเมื่อฉันเพิ่มส่วนหัว: {"cache-control": "no-cache"} ลงใน ajaxSetup มันเพิ่มส่วนหัวของ Cache-Control เป็นสองเท่าเป็น "no-cache, no-cache" - และหยุดการแคช เกิดอะไรขึ้นที่นี่
Tom W Hall

ทำงานได้อย่างสมบูรณ์ - คุณยังสามารถเพิ่มคำขอเป็นพารามิเตอร์ $ .ajax ({ประเภท: 'POST', ส่วนหัว: {'การควบคุมแคช': 'no-cache'}, ฯลฯ })
George Filippakos

[pragma: no-cache] คืออะไร? คีย์ pragma ใช้ทำอะไร
zakdances

ฉันยังคิดว่านี่เป็นวิธีที่ดีที่สุดแทนที่จะแก้ไขปัญหาด้วยพารามิเตอร์เพิ่มเติม เราได้เพิ่มสิ่งนี้ในการโทรที่เราต้องการสำหรับการโทรที่มีผลตอบแทนเท่ากันการแคชน่าจะเป็นสิ่งที่ดีสำหรับผู้ใช้
germankiwi

67

ทางออกที่ง่ายสำหรับการร้องขอบริการเว็บทั้งหมดของคุณโดยสมมติว่าคุณใช้ jQuery:

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
    // you can use originalOptions.type || options.type to restrict specific type of requests
    options.data = jQuery.param($.extend(originalOptions.data||{}, { 
      timeStamp: new Date().getTime()
    }));
});

อ่านเพิ่มเติมเกี่ยวกับการเรียก jQuery Prefilter ที่นี่

หากคุณไม่ได้ใช้ jQuery ให้ตรวจสอบเอกสารของห้องสมุดที่คุณเลือก พวกเขาอาจมีฟังก์ชั่นที่คล้ายกัน


3
มันไม่ทำงานสำหรับฉันเซิร์ฟเวอร์ตอบสนอง: "JSON ดั้งเดิมไม่ถูกต้อง: timeStamp" asp.net / iis 7.5
Alexandre

3
สิ่งที่เกี่ยวกับ $ .ajax ({"แคช": false ... })? จะใช้งานได้เมื่อผนวก a _ = [TIMESTAMP] หรือไม่ (ผมไม่ได้เป็นเจ้าของอุปกรณ์ดังกล่าวไปทดสอบ)
Karussell

ฉันโพสต์การใช้งานโซลูชันที่เสนอโดย Karussell อย่างสมบูรณ์ ดูคำตอบของฉันด้านล่าง
Sam Shiles

1
@Karussell เพิ่งลองตั้งค่า $ .ajax ({"cache": false ... }) สิ่งนี้ไม่ได้แก้ไขปัญหาสำหรับคำขอ POST บน iOS6 สันนิษฐานว่าเป็นเพราะ JQuery ตามเอกสารของพวกเขาถือว่าไม่มีเบราว์เซอร์ที่โง่พอที่จะแคชคำขอโพสต์ "หน้าที่ดึงข้อมูลด้วย POST จะไม่ถูกแคชดังนั้นตัวเลือกแคชและ ifModified ใน jQuery.ajaxSetup () จะไม่มีผลกับการร้องขอเหล่านี้"
เบร็ทฮันนาห์

1
มันใช้งานไม่ได้ มันไม่ได้รวมพารามิเตอร์การโพสต์ โพสต์โดย Dave เป็นทางออกที่ดีกว่า
Chris Muench

43

ฉันเพิ่งมีปัญหานี้เช่นกันในแอปพลิเคชันPhoneGap ฉันแก้ไขมันโดยใช้ฟังก์ชัน JavaScript getTime()ในลักษณะต่อไปนี้:

var currentTime = new Date();
var n = currentTime.getTime();
postUrl = "http://www.example.com/test.php?nocache="+n;
$.post(postUrl, callbackFunction);

ฉันเสียเวลาหาเวลาสองสามชั่วโมง คงจะดีที่ Apple แจ้งให้ผู้พัฒนาทราบถึงปัญหาการแคชนี้


1
ฉันจะแสดงความคิดเห็นในการใช้{cache:false}เป็นตัวเลือกอย่างใดอย่างหนึ่ง$.post()หรือ$.ajaxSetup()แต่ตามเอกสารเอกสารอาร์กิวเมนต์เหล่านี้จะถูกละเว้น; jQuery จะส่งคำขอโพสต์ 'ไม่แคช' แต่ไม่นำเบราว์เซอร์มาพิจารณา บางทีอาจจะเป็นตัวเลือกที่ neater $.ajaxPrefilter()จะเพิ่มการประทับเวลาการร้องขอใช้
fwielstra

ฉันใช้เวลาเกือบ 5 ชั่วโมงเพื่อแก้ไขปัญหานี้และในที่สุดการเพิ่มการประทับเวลาจะทำให้เคล็ดลับfunction send_ajax(my_data,refresh) .. ดูที่นี่stackoverflow.com/questions/14733772/…
rusly

42

ฉันมีปัญหาเดียวกันกับ webapp ที่รับข้อมูลจาก ASP.NET webservice

สิ่งนี้ใช้ได้กับฉัน:

public WebService()
{
    HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    ...
}

2
ขอบคุณมาก! ฉันกำลังบ้าที่จะลองคิดดูว่าทำไม iPhone ถึงแสดงแตกต่างจากแพลตฟอร์มอื่น ๆ โซลูชันเฉพาะ ASP.NET นี้ช่วยฉันได้หลายครั้ง
Mark Brittingham

ใช้งานไม่ได้กับ iOS6 ดูคำตอบของฉันในตอนท้าย
Brian Ogden

1
โปรด!!!! วางเงื่อนไขในการใช้สิ่งนี้เฉพาะใน IOS 6 เนื้อหาแคชมีความสำคัญต่อแอปพลิเคชันใด ๆ
Alexandre

24

ในที่สุดฉันก็มีวิธีแก้ไขปัญหาการอัปโหลดของฉัน

ใน JavaScript:

var xhr = new XMLHttpRequest();
xhr.open("post", 'uploader.php', true);
xhr.setRequestHeader("pragma", "no-cache");

ในPHP :

header('cache-control: no-cache');

15

จากบล็อกของฉันเองโพสต์iOS 6.0 แคชคำขอ Ajax POST :

วิธีแก้ไข: มีวิธีการต่าง ๆ เพื่อป้องกันการแคชคำขอ วิธีที่แนะนำคือการเพิ่มส่วนหัวที่ไม่มีแคช นี่คือวิธีที่มันทำ

jQuery:

ตรวจสอบ iOS 6.0 และตั้งค่าส่วนหัว Ajax ดังนี้:

$.ajaxSetup({ cache: false });

ZeptoJS:

ตรวจสอบ iOS 6.0 และตั้งค่าส่วนหัว Ajax ดังนี้:

$.ajax({
    type: 'POST',
    headers : { "cache-control": "no-cache" },
    url : ,
    data:,
    dataType : 'json',
    success : function(responseText) {…}

ฝั่งเซิร์ฟเวอร์

Java:

httpResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");

ตรวจสอบให้แน่ใจว่าได้เพิ่มที่ด้านบนของหน้าก่อนที่ข้อมูลใด ๆ จะถูกส่งไปยังลูกค้า

.สุทธิ

Response.Cache.SetNoStore();

หรือ

Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);

PHP

header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1.
header('Pragma: no-cache'); // HTTP 1.0.

2
แอตทริบิวต์แคชที่ดีสำหรับ. NET stackoverflow.com/questions/10011780/…
Aran Mulholland

7

ตัวอย่าง JavaScript นี้ทำงานได้ดีกับ jQuery และ jQuery Mobile:

$.ajaxSetup({
    cache: false,
    headers: {
        'Cache-Control': 'no-cache'
    }
});

เพียงวางไว้ที่ไหนสักแห่งในรหัส JavaScript ของคุณ (หลังจากโหลด jQuery และดีที่สุดก่อนที่คุณจะร้องขอ AJAX) และควรช่วย


6

คุณสามารถแก้ไขปัญหานี้ได้ด้วยการแก้ไขjQuery Ajaxฟังก์ชั่นโดยทำดังต่อไปนี้ (ตั้งแต่ 1.7.1) ไปที่ด้านบนของฟังก์ชั่น Ajax (ฟังก์ชั่นเริ่มต้นที่บรรทัด 7212) การเปลี่ยนแปลงนี้จะเปิดใช้งานคุณสมบัติป้องกันแคชในตัวของ jQuery สำหรับคำขอ POST ทั้งหมด

(สคริปต์เต็มมีอยู่ที่ http://dl.dropbox.com/u/58016866/jquery-1.7.1.js )

แทรกบรรทัดด้านล่าง 7221:

if (options.type === "POST") {
    options.cache = false;
}

จากนั้นแก้ไขสิ่งต่อไปนี้ (เริ่มที่บรรทัด ~ 7497)

if (!s.hasContent) {
    // If data is available, append data to URL
    if (s.data) {
        s.url += (rquery.test(s.url) ? "&" : "?") + s.data;
        // #9682: remove data so that it's not used in an eventual retry
        delete s.data;
    }

    // Get ifModifiedKey before adding the anti-cache parameter
    ifModifiedKey = s.url;

    // Add anti-cache in URL if needed
    if (s.cache === false) {
        var ts = jQuery.now(),
        // Try replacing _= if it is there
        ret = s.url.replace(rts, "$1_=" + ts);

        // If nothing was replaced, add timestamp to the end.
        s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
    }
}

ถึง:

// More options handling for requests with no content
if (!s.hasContent) {
    // If data is available, append data to URL
    if (s.data) {
        s.url += (rquery.test(s.url) ? "&" : "?") + s.data;
        // #9682: remove data so that it's not used in an eventual retry
        delete s.data;
    }

    // Get ifModifiedKey before adding the anti-cache parameter
    ifModifiedKey = s.url;
}

// Add anti-cache in URL if needed
if (s.cache === false) {
    var ts = jQuery.now(),
    // Try replacing _= if it is there
    ret = s.url.replace(rts, "$1_=" + ts);

    // If nothing was replaced, add timestamp to the end.
    s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
}

4
ไม่ใช่วิธีที่ดีในการเปลี่ยน jQuery หรือรหัสใด ๆ ก็ตามที่คุณไม่ได้เป็นเจ้าของ (ทุกครั้งที่คุณต้องการอัปเดตเวอร์ชันที่คุณจะต้องทำการเปลี่ยนแปลงอีกครั้ง (หรือการปรับปรุงอื่น ๆ ของนักพัฒนาและโปรแกรมไม่ทำงาน))
andlrc

มันเป็นวิธีการที่ถูกต้องสมบูรณ์แบบหากคุณต้องการวิธีการแก้ปัญหาที่รวดเร็วที่สุดเท่าที่จะเป็นไปได้เพื่อลดความงี่เง่าของ Apple โซลูชันนี้ถูกใช้เพื่อแก้ไขปัญหาสำหรับไซต์ขนาดใหญ่ที่ได้รับการเข้าชมหลายล้านครั้งต่อวันและทำให้เราสามารถทำได้เพียงแค่ทำการเปลี่ยนแปลงไฟล์เดียว
Sam Shiles

คุณสามารถดูjQuery.ajaxPrefilerมันช่วยให้คุณสามารถปรับเปลี่ยนการร้องขอ ajax ของคุณได้ก่อนที่จะทำการ คุณสามารถเก็บถาวรด้วยการเพิ่มประสิทธิภาพและปรับปรุงรหัสปลอดภัย
andlrc

1
ปัญหาเกี่ยวกับวิธี preFilter คือคุณต้องลงทะเบียนตัวกรอง หากคุณมีสคริปต์ทั่วไปที่ทำงานเมื่อแต่ละหน้าโหลดแล้วก็ดี แต่ถ้าคุณไม่ต้องตั้งค่า preFilter สำหรับแต่ละหน้าที่ใช้ ajax สถานการณ์ที่ฉันเผชิญเรามีตำแหน่งทั่วไปสำหรับไฟล์ JQ ที่ใช้เป็นแหล่งข้อมูลสำหรับเว็บไซต์มากกว่า 7 แห่ง เราเสียเงินหลายพันปอนด์ต่อชั่วโมงเนื่องจากข้อผิดพลาดนี้และวิธีการที่ฉันแนะนำทำให้เราสามารถแก้ไขได้ในเวลาที่สั้นที่สุดโดยการเปลี่ยนไฟล์หนึ่งไฟล์ ฉันเห็นด้วยกับคุณในเงินต้น แต่บางครั้งคุณก็ต้องปฏิบัติอย่างจริงจัง!
Sam Shiles

จากนั้นคุณสามารถเพิ่มอีกครั้งในตอนท้ายของไฟล์นั้น ดีที่คุณแก้ไขมัน บริษัท ของคุณต้องมีความสุขสำหรับคุณ
andlrc

5

การแก้ไขปัญหาอย่างรวดเร็วสำหรับบริการ GWT-RPC คือการเพิ่มสิ่งนี้ลงในวิธีการทางไกลทั้งหมด:

getThreadLocalResponse().setHeader("Cache-Control", "no-cache");

พวกเราส่วนใหญ่มีวิธีการทางไกลหลายร้อยวิธีในการปรับใช้ GWT มีวิธีที่เป็นสากลในการตั้งค่าส่วนหัวของการควบคุมแคชสำหรับคำขอทั้งหมดหรือไม่?
dirkoneill

5

นี่คือการอัปเดตคำตอบของ Baz1nga เนื่องจากoptions.dataไม่ใช่วัตถุ แต่เป็นสตริงฉันเพิ่งใช้การเชื่อมเวลาเข้าด้วยกัน:

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
  if (originalOptions.type == "post" || options.type == "post") {

    if (options.data && options.data.length)
      options.data += "&";
    else
      options.data = "";

    options.data += "timeStamp=" + new Date().getTime();
  }
});

1
การเพิ่มการประทับเวลาเป็นความคิดที่ไม่ดีลองโซลูชันของ Dave แทน
Nicholas Shanks

4

ในการแก้ไขปัญหานี้สำหรับ WebApps ที่เพิ่มไปยังหน้าจอหลักคุณจำเป็นต้องปฏิบัติตามวิธีแก้ไขปัญหาทั้งสองที่ได้รับการโหวตสูงสุด การแคชจะต้องปิดการใช้งานบนเว็บเซิร์ฟเวอร์เพื่อป้องกันการร้องขอใหม่จากการถูกแคชไปข้างหน้าและจะต้องเพิ่มการป้อนข้อมูลแบบสุ่มบางส่วนในทุกโพสต์คำขอเพื่อให้คำขอที่ถูกแคชไปแล้ว โปรดอ้างอิงโพสต์ของฉัน:

iOS6 - มีวิธีล้าง ajax POST ที่แคชไว้สำหรับการเพิ่ม webapp ในหน้าจอหลักหรือไม่?

คำเตือน: สำหรับทุกคนที่ใช้วิธีแก้ปัญหาด้วยการเพิ่มการประทับเวลาในคำขอของพวกเขาโดยไม่ต้องปิดการแคชบนเซิร์ฟเวอร์ หากแอปของคุณถูกเพิ่มในหน้าจอหลักตอนนี้ทุกโพสต์การตอบสนองจะถูกแคชล้างแคชซาฟารีไม่ล้างมันและดูเหมือนจะไม่หมดอายุ ดูเหมือนว่าหน่วยความจำอาจรั่วไหล!


คำตอบทั้งหมดจะถูกเก็บไว้ในไฟล์หรือหน่วยความจำบนโทรศัพท์หรือไม่
Eydun

นี่ไม่ใช่กรณีของฉัน ฉันเพิ่มการประทับเวลาต่อท้าย URL ของฉัน (ไม่ใช่พารามิเตอร์การโพสต์) และใช้งานได้ดีทั้งเมื่อเรียกดูจากซาฟารีและเมื่อบันทึกลงในหน้าจอหลัก
ShadeTreeDeveloper

4

สิ่งที่ไม่ทำงานสำหรับฉันด้วย iPad 4 / iOS 6:

คำขอของฉันมี: Cache-Control: no-cache

//asp.net's:
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache)

การเพิ่มแคช: false เพื่อการโทร jQuery ajax ของฉัน

 $.ajax(
        {
            url: postUrl,
            type: "POST",
            cache: false,
            ...

มีเพียงวิธีนี้เท่านั้นที่ใช้เคล็ดลับ:

var currentTime = new Date();
var n = currentTime.getTime();
postUrl = "http://www.example.com/test.php?nocache="+n;
$.post(postUrl, callbackFunction);

การลงคะแนนเสียงคืออะไร? นี่คือแคชข้อมูลสำคัญ: เท็จไม่ได้ทำงานกับ iPad4 / iOS6 มิได้ไม่ //asp.net's: HttpContext.Current.Response.Cache.SetCacheability (HttpCacheability.NoCache)
ไบรอันอ็อกเดน

สำหรับ posterity: ตั้งแต่ปี 2017 $.ajax cache: falseผนวก URL ด้วยพารามิเตอร์การสืบค้น_=Date.prototype.getTime()ดังนั้นการเพิ่มการประทับเวลาด้วยตนเองไม่จำเป็นต้องใช้อีกต่อไป
cowbert

3

นั่นคือการแก้ไขสำหรับ GWT-RPC

class AuthenticatingRequestBuilder extends RpcRequestBuilder 
{
       @Override
       protected RequestBuilder doCreate(String serviceEntryPoint) 
       {
               RequestBuilder requestBuilder = super.doCreate(serviceEntryPoint);           
               requestBuilder.setHeader("Cache-Control", "no-cache");

               return requestBuilder;
       }
}

AuthenticatingRequestBuilder builder = new AuthenticatingRequestBuilder();
((ServiceDefTarget)myService).setRpcRequestBuilder(builder);    

2

วิธีแก้ปัญหาของฉันในASP.NET (pagemethods, เว็บเซอร์อื่น ๆ )

protected void Application_BeginRequest(object sender, EventArgs e)
{
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
}

1

ในขณะที่การเพิ่มพารามิเตอร์ cache-buster เพื่อให้คำขอดูเหมือนแตกต่างกันเป็นโซลูชั่นที่มั่นคงฉันจะแนะนำกับมันเพราะมันจะทำร้ายแอปพลิเคชันใด ๆ ที่อาศัยแคชจริงเกิดขึ้น การทำให้ API ออกมาส่วนหัวที่ถูกต้องเป็นทางออกที่ดีที่สุดแม้ว่าจะยากกว่าการเพิ่มแคชบัสเตอร์ไปยังผู้โทรก็ตาม


1
ในขณะที่ฉันจะเห็นด้วยกับสถานการณ์ส่วนใหญ่ของฉันฉันจะยืนยันว่าวิธีการแก้ปัญหาที่แท้จริงของปัญหานี้คือสำหรับแอปเปิ้ลในการใช้ HTTP อย่างถูกต้อง ด้วยสิ่งนี้ในใจฉันจะไม่โทษนักพัฒนาจำนวนมากสำหรับการนำโซลูชันที่ง่ายที่สุดมาใช้จนถึงเวลานั้น สำหรับฉันการปรับเปลี่ยนการใช้ jquery เป็นวิธีแก้ไขที่ง่ายที่สุดเนื่องจากอนุญาตให้ฉันทำการแก้ไขได้อย่างหนึ่งและมั่นใจได้ว่ามันทำงานได้ทั้งเว็บไซต์ของฉัน
Sam Shiles

1

สำหรับผู้ใช้Struts 1ที่นี่ฉันจะแก้ไขปัญหาได้อย่างไร

web.xml

<filter>
    <filter-name>SetCacheControl</filter-name>
    <filter-class>com.example.struts.filters.CacheControlFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>SetCacheControl</filter-name>
    <url-pattern>*.do</url-pattern>
    <http-method>POST</http-method>
</filter-mapping>

com.example.struts.filters.CacheControlFilter.js

package com.example.struts.filters;

import java.io.IOException;
import java.util.Date;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;

public class CacheControlFilter implements Filter {

        public void doFilter(ServletRequest request, ServletResponse response,
                     FilterChain chain) throws IOException, ServletException {

        HttpServletResponse resp = (HttpServletResponse) response;
        resp.setHeader("Expires", "Mon, 18 Jun 1973 18:00:00 GMT");
        resp.setHeader("Last-Modified", new Date().toString());
        resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");
        resp.setHeader("Pragma", "no-cache");

        chain.doFilter(request, response);
    }

    public void init(FilterConfig filterConfig) throws ServletException {
    }

    public void destroy() {
    }

}

1

ฉันสามารถแก้ไขปัญหาของฉันได้โดยใช้ชุดค่าผสม $ .ajaxSetup และต่อท้ายเวลาเข้ากับ URL ของโพสต์ของฉัน (ไม่รวมพารามิเตอร์ / เนื้อหาโพสต์) นี้ขึ้นอยู่กับคำแนะนำของคำตอบก่อนหน้า

$(document).ready(function(){
    $.ajaxSetup({ type:'POST', headers: {"cache-control","no-cache"}});

    $('#myForm').submit(function() {
        var data = $('#myForm').serialize();
        var now = new Date();
        var n = now.getTime();
        $.ajax({
            type: 'POST',
            url: 'myendpoint.cfc?method=login&time='+n,
            data: data,
            success: function(results){
                if(results.success) {
                    window.location = 'app.cfm';
                } else {
                    console.log(results);
                    alert('login failed');
                }
            }
        });
    });
});

1

ฉันคิดว่าคุณได้แก้ไขปัญหาของคุณแล้ว แต่ให้ฉันแบ่งปันแนวคิดเกี่ยวกับการแคชเว็บ

เป็นเรื่องจริงที่คุณสามารถเพิ่มส่วนหัวจำนวนมากในแต่ละภาษาที่คุณใช้ฝั่งเซิร์ฟเวอร์ฝั่งไคลเอ็นต์และคุณสามารถใช้ลูกเล่นอื่น ๆ อีกมากมายเพื่อหลีกเลี่ยงการแคชเว็บ แต่คิดเสมอว่าคุณไม่สามารถรู้ได้ว่าไคลเอนต์ใดเชื่อมต่อกับเซิร์ฟเวอร์ของคุณ คุณไม่มีทางรู้ว่าเขากำลังใช้การเชื่อมต่อ "จุดร้อน" ของโรงแรมที่ใช้ Squid หรือผลิตภัณฑ์แคชอื่น ๆ

หากผู้ใช้กำลังใช้พร็อกซีเพื่อซ่อนตำแหน่งจริงของเขา ฯลฯ … วิธีเดียวที่แท้จริงในการหลีกเลี่ยงการแคชคือการประทับเวลาในคำขอหากไม่ได้ใช้

ตัวอย่างเช่น:

/ajax_helper.php?ts=3211321456

จากนั้นผู้จัดการแคชทุกคนที่คุณต้องผ่านไม่พบ URL เดียวกันในที่เก็บแคชและไปดาวน์โหลดเนื้อหาของหน้าอีกครั้ง


คำตอบเก่า แต่สองเซ็นต์ของฉัน: นี่เป็นคำแนะนำที่ดีและเป็นที่เข้าใจกันโดยนักพัฒนาเว็บที่มีความสามารถส่วนใหญ่ แต่ในกรณีเฉพาะของ jQuery หากคุณสร้าง$.ajaxและตั้งค่าตัวเลือกให้{cache:false}jQuery นั้นจะเพิ่มแคชโดยอัตโนมัติ เบื้องหลังโดยที่คุณไม่ต้องทำอะไรอีก
JakeGould

0

คุณสามารถแก้ไขปัญหาได้ใน iOS 6 โดยใช้ Safari> Advanced> Web Inspector ทั้งนี้ขึ้นอยู่กับแอพซึ่งจะเป็นประโยชน์กับสถานการณ์นี้

เชื่อมต่อโทรศัพท์กับ Safari บน Mac แล้วใช้เมนูนักพัฒนาซอฟต์แวร์เพื่อแก้ปัญหาในการถ่ายภาพเว็บแอป

ล้างข้อมูลเว็บไซต์บน iPhone หลังจากอัปเดตเป็น iOS6 รวมถึงเฉพาะแอพโดยใช้ Web View มีเพียงแอปเดียวที่มีปัญหาและสิ่งนี้แก้ไขได้ในระหว่างการทดสอบ IOS6 Beta กลับมาตั้งแต่นั้นมาไม่มีปัญหาจริง

คุณอาจต้องดูแอพของคุณด้วยดูที่ NSURLCache หากอยู่ใน WebView ในแอปที่กำหนดเอง

https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSURLCache_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003754

ฉันเดาขึ้นอยู่กับลักษณะที่แท้จริงของปัญหาการใช้งานและอื่น ๆ ..

Ref: $ .ajax call


แม้ว่านี่จะไม่ได้ตอบคำถามเดิมโดยตรง แต่เป็นข้อมูลที่มีประโยชน์มากสำหรับการแก้ไขปัญหาเกี่ยวกับอุปกรณ์โดยทั่วไปดังนั้นฉันจึงลงคะแนน
Kris Giesing

0

ฉันพบวิธีแก้ปัญหาหนึ่งที่ทำให้ฉันอยากรู้ว่าทำไมมันถึงทำงาน ก่อนที่จะอ่านคำตอบของ Tadej เกี่ยวกับบริการเว็บ ASP.NET ฉันพยายามหาสิ่งที่จะทำงาน

และฉันไม่ได้บอกว่ามันเป็นทางออกที่ดี แต่ฉันแค่ต้องการจัดทำเอกสารไว้ที่นี่

หน้าหลัก: รวมถึงฟังก์ชั่น JavaScript, checkStatus () วิธีการนี้เรียกวิธีอื่นซึ่งใช้การเรียก jQuery AJAX เพื่ออัปเดตเนื้อหา html ฉันใช้ setInterval เพื่อโทร checkStatus () แน่นอนฉันพบปัญหาแคช

วิธีแก้ไข: ใช้หน้าอื่นเพื่อเรียกการอัปเดต

ในหน้าหลักฉันตั้งค่าตัวแปรบูลีน runUpdate และเพิ่มสิ่งต่อไปนี้ลงในแท็ก body:

<iframe src="helper.html" style="display: none; visibility: hidden;"></iframe>

ในส่วนของ helper.html:

<meta http-equiv="refresh" content="5">
<script type="text/javascript">
    if (parent.runUpdate) { parent.checkStatus(); }
</script>

ดังนั้นถ้า checkStatus () ถูกเรียกจากหน้าหลักฉันจะได้รับเนื้อหาที่แคช ถ้าฉันเรียก checkStatus จากหน้าย่อยฉันจะได้รับเนื้อหาที่อัปเดต


0

ในขณะที่หน้าเข้าสู่ระบบและการสมัครใช้งานของฉันทำงานได้อย่างยอดเยี่ยมใน Firefox, IE และ Chrome ... ฉันกำลังดิ้นรนกับปัญหานี้ใน Safari สำหรับ IOS และ OSX เมื่อไม่กี่เดือนที่ผ่านมาฉันพบวิธีแก้ปัญหาบน SO

<body onunload="">

หรือทาง javascript

<script type="text/javascript">
window.onunload = function(e){
    e.preventDefault();
    return;
};
</script>   

นี่คือสิ่งที่น่าเกลียด แต่ทำงานได้ในขณะที่

ฉันไม่รู้ว่าทำไม แต่กลับเป็นโมฆะไปที่onunloadกิจกรรมหน้าจะไม่ถูกแคชใน Safari


0

เราพบว่า iPhone และ iPads รุ่นเก่าที่ใช้ iOS เวอร์ชัน 9 & 10 บางครั้งจะส่งคืนผลลัพธ์ AJAX เปล่า ๆ เป็นครั้งคราวซึ่งอาจเป็นผลมาจากการลดความเร็ว CPU ของ Apple เมื่อส่งคืนผลลัพธ์เปล่าเปล่า iOS จะไม่เรียกเซิร์ฟเวอร์ดังเช่นส่งคืนผลลัพธ์จากแคช ความถี่แตกต่างกันอย่างมากจากประมาณ 10% ถึง 30% ของการโทร AJAX กลับว่างเปล่า

วิธีแก้ปัญหานั้นยากที่จะเชื่อ รอ 1 วินาทีแล้วโทรอีกครั้ง ในการทดสอบของเรามีการทำซ้ำเพียงครั้งเดียวเท่านั้นที่จำเป็นทั้งหมด แต่เราเขียนโค้ดเพื่อโทรถึง 4 ครั้ง เราไม่แน่ใจว่าจำเป็นต้องรอ 1 วินาทีหรือไม่ แต่เราไม่ต้องการเสี่ยงที่จะทำให้เซิร์ฟเวอร์ของเราเกิดการโทรซ้ำหลายครั้ง

เราพบปัญหาที่เกิดขึ้นกับการโทร AJAX ที่แตกต่างกันสองการเรียกใช้ไฟล์ API ที่แตกต่างกันที่มีข้อมูลแตกต่างกัน แต่ฉันกังวลว่าอาจเกิดขึ้นกับการโทร AJAX เราไม่รู้เพราะเราไม่ตรวจสอบผลลัพธ์ AJAX ทุกรายการและเราไม่ทดสอบการโทรทุกครั้งบนอุปกรณ์เก่าหลายครั้ง

ปัญหาที่เกิดขึ้นการโทร AJAX ทั้งสองใช้: POST, Asynchronously = true, setRequestHeader = ('ประเภทเนื้อหา', 'แอปพลิเคชัน / x-www-form-urlencoded')

เมื่อเกิดปัญหามักจะมีการโทร AJAX เพียงครั้งเดียว ดังนั้นจึงไม่ได้เกิดจากการโทร AJAX ที่ทับซ้อนกัน บางครั้งปัญหาเกิดขึ้นเมื่ออุปกรณ์ไม่ว่าง แต่บางครั้งไม่และไม่มี DevTools เราไม่รู้จริง ๆ ว่าเกิดอะไรขึ้นในเวลานั้น

iOS 13 ไม่ได้ทำเช่นนี้หรือ Chrome หรือ Firefox เราไม่มีอุปกรณ์ทดสอบใด ๆ ที่ใช้ iOS 11 หรือ 12 บางทีอาจมีคนอื่นทดสอบได้บ้าง

ฉันสังเกตเห็นที่นี่เพราะคำถามนี้เป็นผลการค้นหาอันดับต้น ๆ ของ Google เมื่อค้นหาปัญหานี้



-2

ฉันขอแนะนำวิธีแก้ปัญหาเพื่อปรับเปลี่ยนลายเซ็นของฟังก์ชันให้เป็นดังนี้:

getNewRecordID (intRecordType, strTimestamp) จากนั้นส่งผ่านพารามิเตอร์ TimeStamp เช่นกันและทิ้งค่านั้นในฝั่งเซิร์ฟเวอร์เสมอ วิธีนี้สามารถแก้ไขปัญหาได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.