Safari trên iOS 6 có lưu trữ kết quả $ .ajax không?


1072

Kể từ khi nâng cấp lên iOS 6, chúng tôi thấy chế độ xem web của Safari có quyền tự do $.ajaxgọi các bộ nhớ đệm . Đây là trong bối cảnh của một ứng dụng PhoneGap vì vậy nó đang sử dụng Safari WebView. Các $.ajaxcuộc gọi của chúng tôi là POSTcác phương thức và chúng tôi có bộ đệm được đặt thành false {cache:false}, nhưng điều này vẫn xảy ra. Chúng tôi đã thử thêm thủ công vào TimeStamptiêu đề nhưng không được.

Chúng tôi đã nghiên cứu thêm và thấy rằng Safari chỉ trả về kết quả được lưu trong bộ nhớ cache cho các dịch vụ web có chữ ký hàm là tĩnh và không thay đổi từ cuộc gọi sang cuộc gọi. Ví dụ, hãy tưởng tượng một hàm gọi là:

getNewRecordID(intRecordType)

Hàm này nhận được các tham số đầu vào lặp đi lặp lại, nhưng dữ liệu mà nó trả về sẽ khác nhau mỗi lần.

Phải trong sự vội vàng của Apple để tạo ra iOS 6 zip một cách ấn tượng, họ đã quá hài lòng với cài đặt bộ nhớ cache. Có ai khác thấy hành vi này trên iOS 6 không? Nếu vậy, chính xác những gì gây ra nó?


Cách giải quyết mà chúng tôi tìm thấy là sửa đổi chữ ký hàm thành dạng như sau:

getNewRecordID(intRecordType, strTimestamp)

và sau đó luôn luôn truyền vào một TimeStamptham số, và chỉ loại bỏ giá trị đó ở phía máy chủ. Điều này hoạt động xung quanh vấn đề. Tôi hy vọng điều này sẽ giúp một số linh hồn nghèo khổ khác dành 15 giờ cho vấn đề này như tôi đã làm!


190
Điều này là hoàn toàn gây sốc. Chúng tôi cũng đã dành một vài giờ để cố gắng tìm ra thứ gì đó vừa ngừng hoạt động. Thông tin đăng nhập AJAX của chúng tôi có POST (và cũng có tiêu đề để ngăn chặn bộ nhớ đệm) đang được Safari lưu vào bộ nhớ cache để nó trả về cùng một JSON mà nó đã làm lần trước mà không cần thử máy chủ ... không thể tin được! Chúng tôi sẽ phải hack một bản sửa lỗi, nhưng bạn không bao giờ nên lưu trữ POST, thật điên rồ.
Kieran

16
Đăng giải pháp của bạn dưới dạng câu trả lời thay vì cập nhật cho câu hỏi.
ChrisF

50
Các yêu cầu POST không phải là idempotent, có nghĩa là chúng không nên được lưu trong bộ đệm trừ khi phản hồi đặc biệt khuyên bạn thực hiện thông qua các tiêu đề phản hồi của nó.
James M. Greene

6
Để yêu cầu Apple khắc phục điều này, hãy gửi một lỗi tại bugreport.apple.com . Tôi cũng đã làm như vậy.
Mathias Bynens

11
Mark Nottingham (chủ tịch nhóm làm việc IETF HTTPbis) đã viết một bài đăng blog thú vị về điều này ngày hôm nay: mnot.net/blog/2012/09/24/caching_POST
Benjamin Brizzi

Câu trả lời:


447

Sau một chút điều tra, hóa ra Safari trên iOS6 sẽ lưu các POST mà không có tiêu đề Cache-Control hoặc thậm chí là "Cache-Control: max-age = 0".

Cách duy nhất tôi tìm thấy để ngăn bộ nhớ đệm này xảy ra ở cấp độ toàn cầu thay vì phải hack các truy vấn ngẫu nhiên vào cuối các cuộc gọi dịch vụ là đặt "Kiểm soát bộ đệm: không có bộ đệm".

Vì thế:

  • Không có Tiêu đề kiểm soát bộ đệm hoặc hết hạn = Safari iOS6 sẽ lưu trữ bộ đệm
  • Kiểm soát bộ nhớ cache tối đa tuổi = 0 và hết hạn ngay lập tức = Safari Safari6 sẽ lưu trữ bộ đệm
  • Kiểm soát bộ nhớ cache: no-cache = iOS6 Safari sẽ KHÔNG lưu cache

Tôi nghi ngờ rằng Apple đang tận dụng lợi thế này từ thông số HTTP trong phần 9.5 về POST:

Các phản hồi cho phương thức này không được lưu trong bộ nhớ cache, trừ khi phản hồi bao gồm các trường tiêu đề Kiểm soát bộ đệm hoặc hết hạn thích hợp. Tuy nhiên, phản hồi 303 (Xem Khác) có thể được sử dụng để chỉ đạo tác nhân người dùng truy xuất tài nguyên có thể lưu trong bộ nhớ cache.

Vì vậy, trên lý thuyết bạn có thể lưu trữ các phản hồi POST ... ai biết. Nhưng không có nhà sản xuất trình duyệt nào từng nghĩ rằng nó sẽ là một ý tưởng tốt cho đến bây giờ. Nhưng điều đó KHÔNG tính đến bộ đệm khi không có tiêu đề Bộ điều khiển bộ đệm hoặc hết hạn được đặt, chỉ khi có một số bộ. Vì vậy, nó phải là một lỗi.

Dưới đây là những gì tôi sử dụng ở bên phải cấu hình Apache của mình để nhắm mục tiêu toàn bộ API của mình bởi vì thực tế tôi không muốn lưu trữ bất cứ thứ gì, thậm chí là nhận được. Những gì tôi không biết là làm thế nào để thiết lập điều này chỉ cho POST.

Header set Cache-Control "no-cache"

Cập nhật: Chỉ cần lưu ý rằng tôi đã không chỉ ra rằng đó chỉ là khi POST giống nhau, vì vậy hãy thay đổi bất kỳ dữ liệu POST hoặc URL nào và bạn vẫn ổn. Vì vậy, bạn có thể như đã đề cập ở nơi khác chỉ cần thêm một số dữ liệu ngẫu nhiên vào URL hoặc một chút dữ liệu POST.

Cập nhật: Bạn có thể giới hạn "không có bộ đệm" chỉ ở POST nếu bạn muốn như thế này trong Apache:

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

7
Tôi thấy Apple sẽ đi đâu với điều này, nhưng chúng tôi đang thấy các phản hồi được lưu trong bộ nhớ cache cho các yêu cầu POST ngay cả khi các phản hồi của chúng tôi không bao gồm bất kỳ tiêu đề Kiểm soát bộ đệm hoặc Hết hạn nào. Có phải phiên bản này iOS6 không nên lưu trữ và gửi mọi yêu cầu. Điều này không xảy ra.
Kango_V

138
Một phần của thông số HTTP mà bạn trích dẫn không chứng minh hành vi lưu trữ của iOS 6. Hành vi mặc định phải là không lưu các phản hồi POST (nghĩa là khi tiêu đề "Kiểm soát bộ đệm" không được xác định). Hành vi vi phạm thông số kỹ thuật và nên được coi là một lỗi. Bất cứ ai xây dựng các dịch vụ web api xml / json nên trang trí các phản hồi POST của họ bằng "Kiểm soát bộ đệm: không có bộ đệm" để khắc phục sự cố này.
David H

39
Các yêu cầu POST không phải là idempotent, có nghĩa là chúng không nên được lưu trong bộ đệm trừ khi phản hồi đặc biệt khuyên bạn thực hiện thông qua các tiêu đề phản hồi của nó.
James M. Greene

4
Như David nói, đó là một sự vi phạm rõ ràng đối với câu bạn đã trích dẫn. Nếu không có "Trường tiêu đề kiểm soát bộ đệm hoặc hết hạn", rõ ràng các tiêu đề như vậy rõ ràng không được bao gồm. Tuy nhiên, cuộc điều tra của riêng bạn cho thấy nó lưu trữ trong kịch bản đó. Vui lòng chỉnh sửa câu trả lời của bạn.
Matthew Flaschen

3
Có ai biết kết quả được lưu trong bộ nhớ cache trên thiết bị bao lâu không? Tôi đã thử giết safari và khởi động lại điện thoại của mình, nhưng nó vẫn được lưu trong bộ nhớ cache. Tôi biết nó hoạt động với việc xóa bộ nhớ cache của trình duyệt nhưng tôi tự hỏi sẽ mất bao lâu cho người dùng đã từng gặp sự cố trước khi nó biến mất. Không phải ai cũng sẽ nghĩ đến việc xóa bộ nhớ cache của họ ...
Daniel Hallqvist

146

Tôi hy vọng điều này có thể được sử dụng cho các nhà phát triển khác đập đầu vào tường trên cái này. Tôi thấy rằng bất kỳ điều nào sau đây đều ngăn Safari trên iOS 6 lưu vào bộ đệm phản hồi POST:

  • thêm [kiểm soát bộ đệm: không có bộ đệm] trong các tiêu đề yêu cầu
  • thêm một tham số URL biến như thời gian hiện tại
  • thêm [pragma: no-cache] vào tiêu đề phản hồi
  • thêm [kiểm soát bộ đệm: không có bộ đệm] trong các tiêu đề phản hồi

Giải pháp của tôi là như sau trong Javascript của tôi (tất cả các yêu cầu AJAX của tôi là POST).

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

Tôi cũng thêm tiêu đề [pragma: no-cache] vào nhiều phản hồi trên máy chủ của mình.

Nếu bạn sử dụng giải pháp trên, hãy lưu ý rằng mọi lệnh gọi $ .ajax () bạn thực hiện được đặt thành toàn cục: false sẽ KHÔNG sử dụng các cài đặt được chỉ định trong $ .ajaxSetup (), vì vậy bạn sẽ cần thêm lại các tiêu đề.


4
Đây là giải pháp ĐÚNG cho lỗi. Lỗi là iOS 6 sẽ phục vụ các yêu cầu POST từ bộ nhớ cache thay vì gửi chúng đến máy chủ. Lỗi không phải là nó lưu trữ các phản hồi từ các yêu cầu POST (được phép). Nếu bạn vẫn muốn phản hồi cho các yêu cầu POST được truy xuất từ ​​bộ đệm cho các yêu cầu GET tiếp theo cho URI đó, hãy sử dụng giải pháp này.
Nicholas Shanks

2
Điều này làm việc cho tôi, nhưng tôi không hiểu làm thế nào. Tôi đã chỉ định bộ đệm: false trong ajaxSetup của mình và xem các tiêu đề yêu cầu, sẽ chuyển sang Cache-Control: no-cache và Pragma: no-cache - nhưng nó vẫn sẽ lưu cache trên iPad. Sau đó, khi tôi thêm các tiêu đề: {"cache-control": "no-cache"} vào ajaxSetup, nó sẽ nhân đôi tiêu đề Cache-Control thành "no-cache, no-cache" - và dừng bộ đệm. Chuyện gì đang xảy ra ở đây vậy?
Hội trường Tom W

Hoạt động hoàn hảo - bạn cũng có thể thêm vào yêu cầu dưới dạng tham số $ .ajax ({type: 'POST', tiêu đề: {'cache-control': 'no-cache'}, v.v.)
George Filippakos

[Pragma: no-cache] là gì? Khóa pragma được sử dụng để làm gì?
zakdances

Tôi cũng nghĩ rằng đây là cách tiếp cận tốt nhất, thay vì một cách giải quyết với một tham số bổ sung. Chúng tôi đã thêm điều này vào chỉ các cuộc gọi mà chúng tôi cần, đối với các cuộc gọi luôn có cùng mức trả về, bộ nhớ đệm có lẽ là một điều tốt cho người dùng cuối.
nảy mầm

67

Giải pháp đơn giản cho tất cả các yêu cầu dịch vụ web của bạn, giả sử bạn đang sử dụng 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()
    }));
});

Đọc thêm về lệnh gọi bộ lọc jQuery ở đây .

Nếu bạn không sử dụng jQuery, hãy kiểm tra tài liệu cho thư viện bạn chọn. Chúng có thể có chức năng tương tự.


3
Nó không hoạt động với tôi, máy chủ trả lời: "JSON nguyên thủy không hợp lệ: timeStamp" asp.net / iis 7.5
Alexandre

3
Còn $ .ajax ({"cache": false ...}) thì sao? nó sẽ hoạt động khi nó nối thêm _ = [TIMESTAMP]? (Tôi không sở hữu một thiết bị như vậy để kiểm tra nó)
Karussell

Tôi đã đăng một triển khai đầy đủ các giải pháp được đề xuất bởi Karussell. Xem câu trả lời của tôi dưới đây.
Sam Shiles

1
@Karussell. Chỉ cần thử đặt $ .ajax ({"cache": false ...}). Điều này không giải quyết vấn đề cho các yêu cầu POST trên iOS6. Có lẽ bởi vì JQuery theo tài liệu của họ cho rằng không có trình duyệt nào đủ ngu ngốc để lưu các yêu cầu bài đăng. "Các trang được tìm nạp bằng POST không bao giờ được lưu trong bộ nhớ cache, do đó, các tùy chọn bộ đệm và ifModified trong jQuery.ajaxSetup () không có tác dụng đối với các yêu cầu này."
Brett Hannah

1
Điều này không hoạt động. Nó không hợp nhất các tham số bài. Bài viết của Dave là một giải pháp tốt hơn.
Chris Muench

43

Tôi cũng gặp vấn đề này trong ứng dụng PhoneGap . Tôi đã giải quyết nó bằng cách sử dụng hàm JavaScript getTime()theo cách sau:

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

Tôi đã lãng phí một vài giờ để tìm ra điều này. Apple đã rất vui khi thông báo cho các nhà phát triển về vấn đề lưu trữ này.


1
Tôi sẽ bình luận về việc sử dụng {cache:false}như một tùy chọn cho một trong hai $.post()hoặc $.ajaxSetup(), nhưng theo các tài liệu , những lập luận này sẽ được bỏ qua; jQuery sẽ 'không bao giờ lưu trữ' các yêu cầu bài đăng, nhưng không xem xét trình duyệt. Có lẽ một tùy chọn gọn gàng hơn sẽ là thêm dấu thời gian cho các yêu cầu sử dụng $.ajaxPrefilter().
fwielstra

Tôi dành gần 5 giờ để khắc phục sự cố này và cuối cùng thêm dấu thời gian sẽ thực hiện thủ thuật function send_ajax(my_data,refresh) .. tham khảo tại đây stackoverflow.com/questions/14733772/
Kẻ

42

Tôi gặp vấn đề tương tự với một ứng dụng web lấy dữ liệu từ dịch vụ web ASP.NET

Điều này làm việc cho tôi:

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

2
Cảm ơn rât nhiều! Tôi đã phát điên khi cố gắng tìm ra lý do tại sao iPhone lại hoạt động khác biệt so với mọi nền tảng khác. Giải pháp dành riêng cho ASP.NET này giúp tôi tiết kiệm rất nhiều thời gian.
Mark Britsham

Không hoạt động trên iOS6, hãy xem câu trả lời của tôi về cuối chuỗi
Brian Ogden

1
Xin vui lòng!!!! Đặt một điều kiện để chỉ áp dụng điều này trên iOS 6, bộ đệm nội dung là quan trọng đối với bất kỳ ứng dụng nào.
Alexandre

24

Cuối cùng, tôi có một giải pháp cho vấn đề tải lên của mình.

Trong JavaScript:

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

Trong PHP :

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

15

Từ bài đăng trên blog của riêng tôi iOS 6.0 yêu cầu bộ nhớ cache Ajax POST :

Cách khắc phục: Có nhiều phương pháp khác nhau để ngăn chặn bộ đệm của các yêu cầu. Phương pháp được đề xuất là thêm tiêu đề không có bộ đệm. Đây là cách nó được thực hiện.

jQuery:

Kiểm tra iOS 6.0 và đặt tiêu đề Ajax như thế này:

$.ajaxSetup({ cache: false });

ZeptoJS:

Kiểm tra iOS 6.0 và đặt tiêu đề Ajax như thế này:

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

Phía máy chủ

Java:

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

Đảm bảo thêm phần này ở đầu trang trước khi bất kỳ dữ liệu nào được gửi đến máy khách.

.MẠNG LƯỚI

Response.Cache.SetNoStore();

Hoặc là

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
Một thuộc tính không có bộ đệm tốt cho .NET stackoverflow.com/questions/10011780/ từ
Aran Mulholland

7

Đoạn mã JavaScript này hoạt động tuyệt vời với jQuery và jQuery Mobile:

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

Chỉ cần đặt nó ở đâu đó trong mã JavaScript của bạn (sau khi jQuery được tải và tốt nhất là trước khi bạn thực hiện các yêu cầu AJAX) và nó sẽ giúp ích.


6

Bạn cũng có thể khắc phục sự cố này bằng cách sửa đổi hàm jQuery Ajax bằng cách thực hiện các thao tác sau (kể từ 1.7.1) lên đầu hàm Ajax (hàm bắt đầu từ dòng 7212). Thay đổi này sẽ kích hoạt tính năng chống bộ nhớ cache tích hợp của jQuery cho tất cả các yêu cầu POST.

(Kịch bản đầy đủ có sẵn tại http://dl.dropbox.com/u/58016866/jquery-1.7.1.js .)

Chèn bên dưới dòng 7221:

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

Sau đó sửa đổi các mục sau (bắt đầu từ dòng ~ 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 : "");
    }
}

Đến:

// 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
Đây không phải là một cách tiếp cận tốt để thay đổi jQuery hoặc cho vấn đề đó bất kỳ mã nào bạn không sở hữu. (Mỗi khi bạn muốn cập nhật phiên bản, bạn sẽ phải thực hiện lại thay đổi. (Hoặc Một bản cập nhật dành cho nhà phát triển khác và chương trình không hoạt động))
andlrc

Đó là một cách tiếp cận hoàn toàn hợp lệ nếu bạn cần giải pháp nhanh nhất có thể để giảm thiểu sự ngu ngốc của Apple. Giải pháp này đã được sử dụng để giải quyết vấn đề cho một trang web lớn nhận được hàng triệu lượt truy cập mỗi ngày và nó cho phép chúng tôi làm điều đó chỉ bằng cách thay đổi một tệp.
Sam Shiles

Bạn có thể nhìn vào jQuery.ajaxPrefilernó cho phép bạn sửa đổi yêu cầu ajax của bạn ngay trước khi thực hiện. Bạn có thể lưu trữ tương tự với tối ưu hóa hơn và cập nhật mã an toàn.
andlrc

1
Vấn đề với cách tiếp cận preFilter là bạn cần đăng ký bộ lọc. Nếu bạn có một tập lệnh chung chạy khi mỗi trang tải, thì tốt, nhưng nếu không, bạn sẽ phải thiết lập bộ lọc sơ bộ cho mỗi trang sử dụng ajax. Kịch bản tôi gặp phải, chúng tôi có một vị trí chung cho tệp JQ được sử dụng làm tài nguyên cho hơn 7 trang web riêng lẻ. Chúng tôi đã mất hàng ngàn bảng mỗi giờ do lỗi này và cách tiếp cận tôi đã đề xuất cho phép chúng tôi giải quyết vấn đề này trong thời gian ngắn nhất bằng cách thay đổi MỘT tệp. Tôi đồng ý với bạn trong hiệu trưởng nhưng đôi khi bạn phải thực dụng!
Sam Shiles

Sau đó, bạn có thể thêm nó vào cuối tập tin đó. Tốt bạn giải quyết nó, công ty của bạn phải được hạnh phúc cho bạn.
andlrc

5

Cách nhanh chóng cho các dịch vụ GWT-RPC là thêm điều này vào tất cả các phương thức từ xa:

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

Hầu hết chúng ta có hàng trăm phương thức từ xa trong việc triển khai GWT của họ. Có một cách phổ quát đặt tiêu đề kiểm soát bộ đệm cho tất cả các yêu cầu?
dirkoneill

5

Đây là bản cập nhật câu trả lời của Baz1nga. Vì options.datakhông phải là một đối tượng mà là một chuỗi tôi chỉ dùng để nối dấu thời gian:

$.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
Thêm dấu thời gian là một ý tưởng tồi, thay vào đó hãy thử giải pháp của Dave.
Nicholas Shanks

4

Để giải quyết vấn đề này cho WebApps được thêm vào màn hình chính, cả hai cách giải quyết được bình chọn hàng đầu cần phải được theo dõi. Bộ nhớ đệm cần được tắt trên máy chủ web để ngăn các yêu cầu mới được lưu vào bộ đệm và một số đầu vào ngẫu nhiên cần được thêm vào mỗi yêu cầu bài đăng để các yêu cầu đã được lưu trong bộ nhớ cache. Vui lòng tham khảo bài viết của tôi:

iOS6 - Có cách nào để xóa các yêu cầu POST ajax được lưu trong bộ nhớ cache cho ứng dụng web được thêm vào màn hình chính không?

CẢNH BÁO: cho bất kỳ ai thực hiện cách giải quyết bằng cách thêm dấu thời gian vào yêu cầu của họ mà không tắt bộ đệm trên máy chủ. Nếu ứng dụng của bạn được thêm vào màn hình chính, MỌI phản hồi bài đăng sẽ được lưu vào bộ nhớ cache, xóa bộ nhớ cache safari không xóa nó và dường như nó không hết hạn. Trừ khi ai đó có cách để xóa nó, điều này trông giống như rò rỉ bộ nhớ tiềm năng!


Tất cả các phản hồi sẽ được lưu vào bộ nhớ cache hoặc tập tin trên điện thoại?
Eydun

Đây không phải là trường hợp với tôi. Tôi đã thêm một dấu thời gian vào url của mình (không đăng thông số) và nó hoạt động tốt, cả khi duyệt từ safari và khi lưu vào màn hình chính.
ShadowTreeDeveloper

4

Những điều KHÔNG LÀM VIỆC với tôi với iPad 4 / iOS 6:

Yêu cầu của tôi có chứa: Kiểm soát bộ đệm: không có bộ đệm

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

Thêm bộ đệm: false vào cuộc gọi ajax jQuery của tôi

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

Chỉ có điều này đã lừa

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

Bỏ phiếu cho là gì? Đây là bộ đệm thông tin quan trọng: false không hoạt động với iPad4 / iOS6 và //asp.net's: httpContext.Cản.Response.Cache.SetCachablesility (HttpCachablesility.NoCache)
Brian Ogden

Đối với hậu thế: kể từ năm 2017, việc $.ajax cache: falsethêm url với tham số truy vấn _=Date.prototype.getTime(), do đó, việc gắn thêm dấu thời gian theo cách thủ công sẽ không còn cần thiết nữa.
cowbert

3

Đó là công việc xung quanh cho 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

Cách giải quyết của tôi trong ASP.NET (pagemethods, webservice, v.v.)

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

1

Mặc dù việc thêm các tham số cache-buster để làm cho yêu cầu trông khác nhau có vẻ như là một giải pháp vững chắc, tôi sẽ khuyên bạn nên chống lại nó, vì nó sẽ làm tổn thương bất kỳ ứng dụng nào phụ thuộc vào bộ nhớ đệm thực tế đang diễn ra. Làm cho các API xuất ra các tiêu đề chính xác là giải pháp tốt nhất có thể, ngay cả khi điều đó khó hơn một chút so với việc thêm bộ đệm bộ đệm cho người gọi.


1
Mặc dù tôi đồng ý với bạn trong hầu hết các trường hợp, tôi sẽ lập luận rằng giải pháp thực sự cho vấn đề này là để Apple thực hiện chính xác HTTP. Với suy nghĩ này, tôi sẽ không đổ lỗi cho nhiều nhà phát triển đã triển khai giải pháp đơn giản nhất có thể cho đến thời điểm đó. Đối với tôi, sửa đổi triển khai jquery là cách khắc phục đơn giản nhất vì nó cho phép tôi thực hiện một chỉnh sửa và tự tin rằng nó đã hoạt động cho toàn bộ trang web của tôi.
Sam Shiles

1

Đối với những người sử dụng Struts 1, đây là cách tôi khắc phục vấn đề.

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

Tôi đã có thể khắc phục sự cố của mình bằng cách sử dụng kết hợp $ .ajaxSetup và nối thêm dấu thời gian vào url của bài đăng của tôi (không phải cho các tham số / nội dung bài đăng). Điều này dựa trên các khuyến nghị của câu trả lời trước

$(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

Tôi nghĩ rằng bạn đã giải quyết vấn đề của mình, nhưng hãy để tôi chia sẻ ý tưởng về bộ đệm web.

Đúng là bạn có thể thêm nhiều tiêu đề trong mỗi ngôn ngữ bạn sử dụng, phía máy chủ, phía máy khách và bạn có thể sử dụng nhiều thủ thuật khác để tránh bộ đệm web, nhưng luôn nghĩ rằng bạn không bao giờ có thể biết máy khách đang kết nối với máy chủ của mình từ đâu, bạn không bao giờ biết nếu anh ta đang sử dụng kết nối Khách sạn Hot Hot Spot Spot sử dụng Squid hoặc các sản phẩm bộ nhớ đệm khác.

Nếu người dùng đang sử dụng proxy để che dấu vị trí thực của mình, vv ... những thực cách duy nhất để tránh bộ nhớ đệm là timestamp trong yêu cầu còn nếu là không sử dụng.

Ví dụ:

/ajax_helper.php?ts=3211321456

Sau đó, mọi trình quản lý bộ đệm bạn phải vượt qua không tìm thấy cùng một URL trong kho lưu trữ bộ đệm và tải xuống lại nội dung trang.


Câu trả lời cũ, nhưng hai xu của tôi: Đây thường là lời khuyên tốt và được hiểu bởi hầu hết các nhà phát triển web có thẩm quyền, nhưng trong trường hợp cụ thể của jQuery, nếu bạn thực hiện $.ajaxvà đã đặt các tùy chọn thành {cache:false}thì jQuery sẽ tự động thêm bộ đệm ẩn bộ đệm đằng sau hậu trường mà không bao giờ bạn cần phải làm gì khác.
JakeGould

0

Tùy thuộc vào ứng dụng, bạn có thể xử lý sự cố ngay bây giờ trong iOS 6 bằng Safari> Advanced> Web Inspector để có ích với tình huống này.

Kết nối điện thoại với Safari trên máy Mac và sau đó sử dụng menu nhà phát triển để xử lý sự cố khi quay ứng dụng web.

Xóa dữ liệu trang web trên iPhone sau khi cập nhật lên iOS6, bao gồm cụ thể cho ứng dụng bằng Chế độ xem web. Chỉ có một ứng dụng có vấn đề và điều này đã giải quyết nó trong quá trình thử nghiệm IOS6 Beta, kể từ đó không có vấn đề thực sự.

Bạn cũng có thể cần phải xem ứng dụng của mình, hãy xem NSURLCache nếu trong WebView trong một ứng dụng tùy chỉnh.

https://developer.apple.com/l Library / ios

Tôi đoán tùy thuộc vào bản chất thực sự của vấn đề, cách thực hiện, v.v.

Tham chiếu: $ .ajax cuộc gọi


Mặc dù điều này không trực tiếp giải quyết câu hỏi ban đầu, nhưng thông tin rất hữu ích để có thể khắc phục sự cố trên thiết bị nói chung, vì vậy tôi đang bỏ phiếu.
Kris Giesing

0

Tôi tìm thấy một cách giải quyết khiến tôi tò mò về lý do tại sao nó hoạt động. Trước khi đọc câu trả lời của Tadej liên quan đến dịch vụ web ASP.NET, tôi đã cố gắng đưa ra một cái gì đó sẽ hoạt động.

Và tôi không nói rằng đó là một giải pháp tốt, nhưng tôi chỉ muốn ghi lại ở đây.

trang chính: bao gồm hàm JavaScript, checkStatus (). Phương thức gọi một phương thức khác sử dụng lệnh gọi AJAX của jQuery để cập nhật nội dung html. Tôi đã sử dụng setInterval để gọi checkStatus (). Tất nhiên, tôi gặp vấn đề về bộ nhớ đệm.

Giải pháp: sử dụng một trang khác để gọi cập nhật.

Trên trang chính, tôi đặt biến boolean, runUpdate và thêm các mục sau vào thẻ body:

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

Trong helper.html:

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

Vì vậy, nếu checkStatus () được gọi từ trang chính, tôi sẽ nhận được nội dung được lưu trữ. Nếu tôi gọi checkStatus từ trang con, tôi sẽ nhận được nội dung cập nhật.


0

Mặc dù các trang đăng nhập và đăng ký của tôi hoạt động như một cơ duyên trong Firefox, IE và Chrome ... Tôi đã phải vật lộn với vấn đề này trong Safari cho iOS và OSX, vài tháng trước tôi đã tìm thấy một cách giải quyết trên SO.

<body onunload="">

HOẶC qua javascript

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

Đây là một điều xấu xí nhưng làm việc trong một thời gian.

Tôi không biết tại sao, nhưng trả về null cho onunloadsự kiện trang không được lưu trong bộ nhớ cache trong Safari.


0

Chúng tôi thấy rằng iPhone và iPad cũ hơn, chạy phiên bản iOS 9 & 10, đôi khi trả lại kết quả AJAX trống không có thật, có lẽ do Apple giảm tốc độ CPU. Khi trả về kết quả trống, iOS không gọi máy chủ, như thể trả về kết quả từ bộ đệm. Tần suất rất khác nhau, từ khoảng 10% đến 30% các cuộc gọi AJAX trở về trống.

Giải pháp thật khó tin. Chỉ cần đợi 1 giây và gọi lại. Trong thử nghiệm của chúng tôi, chỉ một lần lặp lại là tất cả những gì cần thiết, nhưng chúng tôi đã viết mã để gọi tới 4 lần. Chúng tôi không chắc chắn nếu chờ đợi 1 giây là bắt buộc, nhưng chúng tôi không muốn mạo hiểm gánh nặng máy chủ của chúng tôi với hàng loạt các cuộc gọi lặp đi lặp lại.

Chúng tôi đã tìm thấy sự cố xảy ra với hai cuộc gọi AJAX khác nhau, gọi các tệp API khác nhau với dữ liệu khác nhau. Nhưng tôi lo ngại điều đó có thể xảy ra với bất kỳ cuộc gọi AJAX nào. Chúng tôi chỉ không biết vì chúng tôi không kiểm tra mọi kết quả AJAX và chúng tôi không kiểm tra mọi cuộc gọi nhiều lần trên các thiết bị cũ.

Cả hai vấn đề cuộc gọi AJAX đều đang sử dụng: POST, Asynynciously = true, setRequestHeader = ('Content-Type', 'application / x-www-form-urlencoding')

Khi sự cố xảy ra, thường chỉ có một cuộc gọi AJAX diễn ra. Vì vậy, đó không phải là do các cuộc gọi AJAX chồng chéo. Đôi khi sự cố xảy ra khi thiết bị bận, nhưng đôi khi không, và không có DevTools, chúng tôi không thực sự biết điều gì đang xảy ra vào thời điểm đó.

iOS 13 không làm điều này, cũng không phải Chrome hay Firefox. Chúng tôi không có bất kỳ thiết bị thử nghiệm nào chạy iOS 11 hoặc 12. Có lẽ ai đó có thể kiểm tra những thiết bị đó?

Tôi lưu ý điều này ở đây vì câu hỏi này là kết quả hàng đầu của Google khi tìm kiếm vấn đề này.


-1

Nó chỉ hoạt động với ASP.NET sau khi thêm pragma:no-cachetiêu đề trong IIS . Cache-Control: no-cacheKhông đủ.


-2

Tôi đề nghị một cách giải quyết để sửa đổi chữ ký hàm thành một cái gì đó như thế này:

getNewRecordID (intRecordType, strTimestamp) và sau đó luôn luôn chuyển tham số TimeStamp, và chỉ loại bỏ giá trị đó ở phía máy chủ. Điều này hoạt động xung quanh vấn đề.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.