your programing

iOS 6의 Safari가 $ .ajax 결과를 캐싱합니까?

lovepro 2020. 9. 27. 13:30
반응형

iOS 6의 Safari가 $ .ajax 결과를 캐싱합니까?


iOS 6으로 업그레이드 한 이후로 Safari의 웹보기는 캐싱 $.ajax호출 의 자유를 누리고 있습니다. 이것은 PhoneGap 애플리케이션의 컨텍스트에 있으므로 Safari WebView를 사용합니다. 우리의 $.ajax호출은 POST메서드이고 캐시가 false로 설정되어 {cache:false}있지만 여전히 이런 일이 발생합니다. TimeStamp헤더에 a 수동으로 추가하려고했지만 도움이되지 않았습니다.

더 많은 연구를 수행 한 결과 Safari는 정적이며 호출마다 변경되지 않는 함수 서명이있는 웹 서비스에 대해서만 캐시 된 결과를 반환한다는 사실을 발견했습니다. 예를 들어 다음과 같은 함수를 상상해보십시오.

getNewRecordID(intRecordType)

이 함수는 동일한 입력 매개 변수를 반복해서 수신하지만 반환되는 데이터는 매번 달라야합니다.

iOS 6을 인상적으로 만들려면 Apple이 서두르고 있어야합니다. 그들은 캐시 설정에 너무 만족했습니다. iOS 6에서이 동작을 본 사람이 있습니까? 그렇다면 정확히 무엇이 원인입니까?


우리가 찾은 해결 방법은 함수 서명을 다음과 같이 수정하는 것입니다.

getNewRecordID(intRecordType, strTimestamp)

그런 다음 항상 TimeStamp매개 변수도 전달 하고 서버 측에서 해당 값을 버립니다. 이것은 문제를 해결합니다. 나는 이것이 내가 한 것처럼이 문제에 15 시간을 보내는 다른 가난한 영혼에게 도움이되기를 바랍니다!


약간의 조사 끝에 iOS6의 Safari는 Cache-Control 헤더가 없거나 "Cache-Control : max-age = 0"이없는 POST를 캐시합니다.

서비스 호출 끝에서 임의의 쿼리 문자열을 해킹하지 않고이 캐싱이 전역 수준에서 발생하지 않도록 방지하는 유일한 방법은 "Cache-Control : no-cache"를 설정하는 것입니다.

그래서:

  • Cache-Control 또는 Expires 헤더 없음 = iOS6 Safari가 캐시합니다.
  • Cache-Control max-age = 0 및 즉시 Expires = iOS6 Safari가 캐시합니다.
  • Cache-Control : no-cache = iOS6 Safari는 캐시하지 않습니다.

나는 Apple이 POST에 관한 섹션 9.5의 HTTP 사양에서 이것을 활용하고 있다고 생각합니다.

이 메서드에 대한 응답은 응답에 적절한 Cache-Control 또는 Expires 헤더 필드가 포함되어 있지 않으면 캐시 할 수 없습니다. 그러나 303 (기타 참조) 응답을 사용하여 사용자 에이전트가 캐시 가능한 리소스를 검색하도록 지시 할 수 있습니다.

따라서 이론적으로 POST 응답을 캐시 할 수 있습니다. 그러나 다른 브라우저 제작자는 지금까지 이것이 좋은 아이디어라고 생각한 적이 없습니다. 그러나 Cache-Control 또는 Expires 헤더가 설정되지 않은 경우 캐싱을 고려하지 않고 일부 세트가있을 때만 해당됩니다. 그래서 그것은 버그 일 것입니다.

아래는 아파치 구성의 오른쪽 부분에서 API 전체를 대상으로 사용하는 것입니다. 왜냐하면 실제로는 아무것도 캐시하고 싶지 않기 때문입니다. 내가 모르는 것은 POST를 위해 이것을 설정하는 방법입니다.

Header set Cache-Control "no-cache"

업데이트 : POST가 동일 할 때만 지적하지 않았으므로 POST 데이터 또는 URL을 변경하면 괜찮습니다. 따라서 다른 곳에서 언급했듯이 URL이나 POST 데이터에 임의의 데이터를 추가 할 수 있습니다.

업데이트 : Apache에서 원하는 경우 "no-cache"를 POST로 제한 할 수 있습니다.

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

나는 이것이 다른 개발자가 이것의 벽에 머리를 두드리는 데 유용 할 수 있기를 바랍니다. 다음 중 하나가 iOS 6의 Safari가 POST 응답을 캐싱하지 못하게하는 것을 발견했습니다.

  • 요청 헤더에 [cache-control : no-cache] 추가
  • 현재 시간과 같은 가변 URL 매개 변수 추가
  • 응답 헤더에 [pragma : no-cache] 추가
  • 응답 헤더에 [cache-control : no-cache] 추가

내 솔루션은 Javascript에서 다음과 같습니다 (모든 AJAX 요청은 POST입니다).

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

또한 많은 서버 응답에 [pragma : no-cache] 헤더를 추가합니다.

위의 솔루션을 사용하는 경우 global : false로 설정된 모든 $ .ajax () 호출은 $ .ajaxSetup ()에 지정된 설정을 사용하지 않으므로 헤더를 다시 추가해야합니다.


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 사전 필터 호출에 대해 자세히 알아보십시오 .

jQuery를 사용하지 않는 경우 선택한 라이브러리에 대한 문서를 확인하십시오. 유사한 기능을 가질 수 있습니다.


PhoneGap 애플리케이션 에서도이 문제가 발생했습니다 . getTime()다음과 같은 방식으로 JavaScript 함수 사용하여 해결했습니다 .

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

나는 이것을 알아내는 데 몇 시간을 낭비했습니다. 이 캐싱 문제를 개발자에게 알리는 것은 Apple에게 좋았을 것입니다.


ASP.NET 웹 서비스에서 데이터를 가져 오는 웹 앱에서 동일한 문제가 발생했습니다.

이것은 나를 위해 일했습니다.

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

마지막으로 업로드 문제에 대한 해결책이 있습니다.

JavaScript에서 :

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

에서 PHP :

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

내 블로그 게시물 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) {…}

서버 측

자바:

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.

이 JavaScript 스 니펫은 jQuery 및 jQuery Mobile에서 훌륭하게 작동합니다.

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

JavaScript 코드의 어딘가에 배치하면됩니다 (jQuery가로드 된 후, AJAX 요청을 수행하기 전에 가장 좋음).


Ajax 함수 (기능은 7212 행에서 시작)의 맨 위에 다음 (1.7.1 기준)을 수행 하여 jQuery Ajax 함수를 수정하여이 문제를 해결할 수도 있습니다 . 이 변경 사항은 모든 POST 요청에 대해 jQuery의 내장 캐시 방지 기능을 활성화합니다.

(전체 스크립트는에서 볼 수 있습니다 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 : "");
}

GWT-RPC 서비스에 대한 빠른 해결 방법은 모든 원격 메소드에이를 추가하는 것입니다.

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

이것은 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();
  }
});

홈 화면에 추가 된 웹 애플리케이션에 대해이 문제를 해결하려면 가장 많이 득표 한 두 해결 방법을 모두 따라야합니다. 새로운 요청이 앞으로 캐싱되는 것을 방지하기 위해 웹 서버에서 캐싱을 꺼야하며, 이미 캐싱 된 요청이 통과하려면 모든 포스트 요청에 임의의 입력을 추가해야합니다. 내 게시물을 참조하십시오 :

iOS6-홈 화면에 추가 된 webapp에 대해 캐시 된 ajax POST 요청을 지우는 방법이 있습니까?

경고 : 서버에서 캐싱을 끄지 않고 요청에 타임 스탬프를 추가하여 해결 방법을 구현 한 모든 사람에게. 앱이 홈 화면에 추가되면 모든 게시물 응답이 이제 캐시되고 Safari 캐시를 지워도 지워지지 않으며 만료되지 않는 것 같습니다. 누군가가 그것을 지울 방법이 없다면, 이것은 잠재적 인 메모리 누수처럼 보입니다!


이것이 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);    

iPad 4 / iOS 6에서 나에게 적합 하지 않은:

내 요청에 포함 된 내용 : Cache-Control : no-cache

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

캐시 추가 : jQuery ajax 호출에 false

 $.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);

ASP.NET의 해결 방법 (페이지 메서드, 웹 서비스 등)

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

요청을 다르게 보이게하기 위해 캐시 버스터 매개 변수를 추가하는 것은 견고한 솔루션처럼 보이지만 실제로 발생하는 캐싱에 의존하는 모든 응용 프로그램을 손상시킬 수 있으므로 이에 대해 권장하지 않습니다. API가 올바른 헤더를 출력하도록하는 것이 호출자에게 캐시 버스터를 추가하는 것보다 약간 더 어려운 경우에도 최상의 솔루션입니다.


를 사용하는 사람들을 위해 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() {
    }

}

I was able to fix my problem by using a combination of $.ajaxSetup and appending a timestamp to the url of my post (not to the post parameters/body). This based on the recommendations of previous answers

$(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');
                }
            }
        });
    });
});

I think you have already resolved your issue, but let me share an idea about web caching.

It is true you can add many headers in each language you use, server side, client side, and you can use many other tricks to avoid web caching, but always think that you can never know from where the client are connecting to your server, you never know if he are using a Hotel “Hot-Spot” connection that uses Squid or other caching products.

If the users are using proxy to hide his real position, etc… the real only way to avoid caching is the timestamp in the request also if is unused.

For example:

/ajax_helper.php?ts=3211321456

Then every cache manager you have to pass didnt find the same URL in the cache repository and go re-download the page content.


Depending on the app you can trouble shoot the issue now in iOS 6 using Safari>Advanced>Web Inspector so that is helpful with this situation.

Connect the phone to Safari on a Mac an then use the developer menu to trouble shoot the web app.

Clear the website data on the iPhone after update to iOS6, including specific to the app using a Web View. Only one app had an issue and this solved it during IOS6 Beta testing way back, since then no real problems.

You may need to look at your app as well, check out NSURLCache if in a WebView in a custom app.

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

I guess depending on the true nature of your problem, implementation, etc. ..

Ref: $.ajax calls


I found one workaround that makes me curious as to why it works. Before reading Tadej's answer concerning ASP.NET web service, I was trying to come up with something that would work.

And I'm not saying that it's a good solution, but I just wanted to document it here.

main page: includes a JavaScript function, checkStatus(). The method calls another method which uses a jQuery AJAX call to update the html content. I used setInterval to call checkStatus(). Of course, I ran into the caching problem.

Solution: use another page to call the update.

On the main page, I set a boolean variable, runUpdate, and added the following to the body tag:

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

In the of helper.html:

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

So, if checkStatus() is called from the main page, I get the cached content. If I call checkStatus from the child page, I get updated content.


While my login and signup pages works like a charm in Firefox, IE and Chrome... I've been struggling with this issue in Safari for IOS and OSX, few months ago I found a workaround on the SO.

<body onunload="">

OR via javascript

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

This is kinda ugly thing but works for a while.

I don't know why, but returning null to the onunload event the page do not get cached in Safari.


In Ruby's Sinatra

before '*' do
  if env['REQUEST_METHOD'] == 'POST'
    headers 'Cache-Control' => 'no-cache, no-store, must-revalidate'
  end
end

It worked with ASP.NET only after adding the pragma:no-cache header in IIS. Cache-Control: no-cache was not enough.


I suggest a workaround to modify the function signature to be something like this:

getNewRecordID(intRecordType, strTimestamp) and then always pass in a TimeStamp parameter as well, and just discard that value on the server side. This works around the issue.

참고URL : https://stackoverflow.com/questions/12506897/is-safari-on-ios-6-caching-ajax-results

반응형