ปัญหาการแคช IE เชิงมุมสำหรับ $ http


251

การโทร ajax ทั้งหมดที่ส่งจาก IE จะถูกแคชโดย Angular และฉันจะได้รับ304 responseการโทรตามมาทั้งหมด แม้ว่าคำขอจะเหมือนกัน แต่การตอบกลับจะไม่เหมือนกันในกรณีของฉัน ฉันต้องการปิดการใช้งานแคชนี้ ฉันลองเพิ่มในcache attribute$ http.get แต่ก็ยังไม่ช่วย ปัญหานี้จะแก้ไขได้อย่างไร?

คำตอบ:


439

แทนที่จะปิดใช้งานการแคชสำหรับคำขอ GET แต่ละคำขอฉันจะปิดการใช้งานทั่วโลกใน $ httpProvider:

myModule.config(['$httpProvider', function($httpProvider) {
    //initialize get if not there
    if (!$httpProvider.defaults.headers.get) {
        $httpProvider.defaults.headers.get = {};    
    }    

    // Answer edited to include suggestions from comments
    // because previous version of code introduced browser-related errors

    //disable IE ajax request caching
    $httpProvider.defaults.headers.get['If-Modified-Since'] = 'Mon, 26 Jul 1997 05:00:00 GMT';
    // extra
    $httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache';
    $httpProvider.defaults.headers.get['Pragma'] = 'no-cache';
}]);

78
If-Modified-Sinceทำให้ส่วนหัวของ IIS + iisnode โยน 400 ร้องขอไม่ถูกต้องสำหรับทุกไฟล์ html โหลดผ่านและngInclude ngViewส่วนหัวสองรายการต่อไปนี้แก้ไขปัญหาสำหรับฉัน (ฉันดึงออกมาจาก Chrome ซึ่งไม่มีปัญหาการแคช): $httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache'; $httpProvider.defaults.headers.get['Pragma'] = 'no-cache';
Langdon

4
ในความเห็นของฉันคำตอบนี้ควรถูกทำเครื่องหมายเป็นคำตอบในขณะที่วิธีการแก้ปัญหาที่มาร์ตินใช้งานได้มันเป็นแฮ็คมากกว่าการแก้ไขจริง
Robba

4
สิ่งนี้ใช้ได้กับคำขอ GET ในพื้นที่ของฉัน แต่มันทำให้ CORS หนึ่งคำขอที่ฉันทำเพื่อเริ่มใช้วิธี OPTIONS แทนวิธี GET เซิร์ฟเวอร์บุคคลที่สามไม่สนับสนุนวิธี OPTIONS ดังนั้นวิธีแก้ปัญหาของฉันคือใช้ jQuery.get () เพื่อร้องขอและใช้ $ scope.apply () ในตัวจัดการการตอบกลับ
Ben

13
การใช้งานของการIf-Modified-Since = "0"แบ่งส่วนหัว Tomcat (ปัญหาเกี่ยวกับการแยกวันที่ส่วนหัวเนื่องจาก0ไม่ใช่ค่าRFC ที่ถูกต้อง) แก้ไขโดยใช้ค่าMon, 26 Jul 1997 05:00:00 GMTแทน
lopisan

6
ฉันไม่ได้ใช้ส่วนหัว "If-Modified-Since" และใช้ไม่ได้ อีกสองคนเป็นสิ่งที่จำเป็น
Michael Mahony

69

คุณสามารถต่อท้ายการสืบค้นที่ไม่ซ้ำกัน (ฉันเชื่อว่านี่คือสิ่งที่ jQuery ทำกับแคช: ตัวเลือกเท็จ) ต่อคำขอ

$http({
    url: '...',
    params: { 'foobar': new Date().getTime() }
})

ทางออกที่ดีกว่าคือถ้าคุณเข้าถึงเซิร์ฟเวอร์จากนั้นคุณสามารถตรวจสอบให้แน่ใจว่าได้ตั้งค่าส่วนหัวที่จำเป็นเพื่อป้องกันการแคช หากคุณใช้ASP.NET MVC คำตอบนี้อาจช่วยได้


2
$http.get(url+ "?"+new Date().toString())เป็นเพียงการแสดงอื่นโดยไม่ใช้พารามิเตอร์ แต่เพิ่มลงในสตริงการสืบค้น
Davut Gürbüz

28

คุณอาจเพิ่มตัวดัก

myModule.config(['$httpProvider', function($httpProvider) {
 $httpProvider.interceptors.push('noCacheInterceptor');
}]).factory('noCacheInterceptor', function () {
            return {
                request: function (config) {
                    console.log(config.method);
                    console.log(config.url);
                    if(config.method=='GET'){
                        var separator = config.url.indexOf('?') === -1 ? '?' : '&';
                        config.url = config.url+separator+'noCache=' + new Date().getTime();
                    }
                    console.log(config.method);
                    console.log(config.url);
                    return config;
               }
           };
    });

คุณควรลบบรรทัด console.log หลังจากตรวจสอบ


และคุณควรใช้$logในกรณีที่คุณลืมที่จะนำออก
Carl G

2
ฉันมีปัญหาการแคชที่ร้ายแรงใน IE ซึ่งนำไปสู่หน้าว่างเนื่องจากส่วนสำคัญไม่ได้ทำงาน การใช้ interceptor ที่มีอุปกรณ์ประกอบฉากช่วยแก้ปัญหานี้ได้! +1
raoulinski

ฉันคิดว่านี่เป็นวิธีที่ดีที่สุดเนื่องจากจะหลีกเลี่ยงปัญหาเกี่ยวกับ CORS และ IE ในการเรียกใช้การร้องขอ preflight ถ้าคุณเพิ่มส่วนหัวเพิ่มเติม นี่น่าจะเป็นวิธีที่ปลอดภัยที่สุดที่จะไม่พบปัญหาเพิ่มเติม
chrismarx

@dipip pattnaik: - ทำไมปัญหานี้เกิดขึ้นกับมุมและนั่นคืออะไร?
MiHawk

14

ฉันเพิ่งเพิ่มเมตาแท็กสามแท็กใน index.html ในโครงการเชิงมุมและปัญหาแคชถูกแก้ไขใน IE

<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="Sat, 01 Dec 2001 00:00:00 GMT">

2
เรามีเมตาแท็กเหล่านั้นอยู่แล้วindex.htmlเมื่อเราสังเกตว่า IE11 กำลังแคชคำขอ AJAX: / ​​แต่การกำหนดค่า$httpProviderตามที่แสดงในคำตอบอื่น ๆ ใช้งานได้ดี
walen

14

การทำสำเนาคำตอบของฉันในหัวข้ออื่น

สำหรับAngular 2 และใหม่กว่าวิธีที่ง่ายที่สุดในการเพิ่มno-cacheส่วนหัวโดยการแทนที่RequestOptions:

import { Injectable } from '@angular/core';
import { BaseRequestOptions, Headers } from '@angular/http';

@Injectable()
export class CustomRequestOptions extends BaseRequestOptions {
    headers = new Headers({
        'Cache-Control': 'no-cache',
        'Pragma': 'no-cache',
        'Expires': 'Sat, 01 Jan 2000 00:00:00 GMT'
    });
}

และอ้างอิงในโมดูลของคุณ:

@NgModule({
    ...
    providers: [
        ...
        { provide: RequestOptions, useClass: CustomRequestOptions }
    ]
})

สิ่งเหล่านี้จะไม่เป็นส่วนหัวสำหรับการตอบกลับของเซิร์ฟเวอร์ไม่ใช่สำหรับคำขอของเบราว์เซอร์ (ผมสามารถจินตนาการหนึ่งสามารถตั้งค่าIf-Modified-Sinceที่มีวันบางห่างไกลในอดีตที่ผ่านมาโดยใช้วิธีการดังกล่าว.)
Arjan

@Vitaliy: - ทำไมปัญหานี้เกิดขึ้นกับเชิงมุมและเช่น?
MiHawk

วิธีการของคุณจะลบส่วนหัวที่กำหนดเองที่มีอยู่แล้ว ดังนั้นทำดังต่อไปนี้แทนที่จะสร้างวัตถุส่วนหัวใหม่ headers: req.headers .set('Cache-Control', 'no-cache') .set('Pragma', 'no-cache') .set('Expires', 'Sat, 01 Jan 2000 00:00:00 GMT')
Chamika Goonetilaka

9

สิ่งที่รับประกันได้ว่าฉันทำงานอยู่นั้นมีบางอย่างที่สอดคล้องกัน:

myModule.config(['$httpProvider', function($httpProvider) {
    if (!$httpProvider.defaults.headers.common) {
        $httpProvider.defaults.headers.common = {};
    }
    $httpProvider.defaults.headers.common["Cache-Control"] = "no-cache";
    $httpProvider.defaults.headers.common.Pragma = "no-cache";
    $httpProvider.defaults.headers.common["If-Modified-Since"] = "Mon, 26 Jul 1997 05:00:00 GMT";
}]);

ผมต้องผสาน 2 ของการแก้ปัญหาดังกล่าวข้างต้นเพื่อให้การรับประกันการใช้งานที่ถูกต้องสำหรับวิธีการทั้งหมด แต่คุณสามารถแทนที่commonด้วยgetหรือวิธีการอื่น ๆ เช่นput, post, deleteเพื่อให้งานนี้สำหรับกรณีที่แตกต่างกัน


คุณสามารถบอกฉันได้ว่าในรหัสที่คุณเพิ่มไปยังไฟล์ angular.js หรือไม่ บรรทัด # คืออะไร
JonathanScialpi

@JonathanScialpi ฉันอัปเดตมันเพื่อแสดงตำแหน่งที่ฉันสามารถวางไว้ มันอยู่ที่ไหนในฟังก์ชั่นที่ไม่ระบุชื่อไม่สำคัญ
markyzm

@marksyzm can u กรุณาบอกฉันว่าความหมายของบรรทัดนี้คืออะไรif (!$httpProvider.defaults.headers.get) { $httpProvider.defaults.headers.common = {}; }
Monojit Sarkar

@MonojitSarkar Ah ที่ควรจะเป็น headers.common ในคำสั่ง if ขอบคุณสำหรับตัวชี้นั้น
markyzm

1
["If-Modified-Since"] = "0"เป็นสิ่งผิดกฎหมายและด้วยการสร้างคำขอที่ไม่ดีในบางหลัง มันควรจะเป็นวันที่
jenson-button-event

8

บรรทัดนี้เท่านั้นที่ช่วยฉัน (Angular 1.4.8):

$httpProvider.defaults.headers.common['Pragma'] = 'no-cache';

UPD:ปัญหาคือ IE11 ทำการแคชที่ก้าวร้าว เมื่อฉันดู Fiddler ฉันสังเกตเห็นว่าในคำขอโหมด F12 กำลังส่ง "Pragma = no-cache" และมีการร้องขอจุดสิ้นสุดทุกครั้งที่ฉันเข้าชมหน้าเว็บ แต่ในปลายทางโหมดปกติถูกขอเพียงครั้งเดียวในครั้งแรกเมื่อฉันเข้าเยี่ยมชมหน้า


1
เพียงแค่ FYI คำตอบนี้ทำให้เกิดปัญหา CORS เมื่อขอไฟล์จากหน่วยเก็บข้อมูลหยดสีฟ้าของ Azure ยากที่จะติดตาม แต่ในที่สุดก็พบว่านี่เป็นสาเหตุ การลบส่วนหัว pragma แก้ไขปัญหา CORS ของฉัน (แต่กลับมาใช้งานปัญหาการแคช IE อีกครั้ง)
keithl8041

7

เพื่อหลีกเลี่ยงการแคชหนึ่งตัวเลือกคือการให้ URL ที่แตกต่างกันสำหรับทรัพยากรหรือข้อมูลเดียวกัน หากต้องการสร้าง URL ที่แตกต่างกันคุณสามารถเพิ่มสตริงการสืบค้นแบบสุ่มที่ส่วนท้ายของ URL เทคนิคนี้ใช้ได้กับคำขอ ajax ของ JQuery, Angular หรืออื่น ๆ

myURL = myURL +"?random="+new Date().getTime();

6

ฉันได้รับการแก้ไขต่อท้าย datetime เป็นหมายเลขสุ่ม:

$http.get("/your_url?rnd="+new Date().getTime()).success(function(data, status, headers, config) {
    console.log('your get response is new!!!');
});

: - ทำไมปัญหานี้เกิดขึ้นกับเชิงมุมและเช่น?
MiHawk

4

วิธีแก้ปัญหาข้างต้นจะใช้งานได้ (ทำให้ url ไม่ซ้ำใครด้วยการเพิ่ม querystring param ใหม่) แต่ฉันชอบวิธีแก้ปัญหาที่เสนอ [ที่นี่]: วิธีที่ดีกว่าในการป้องกัน IE Cache ใน AngularJS? ซึ่งจัดการสิ่งนี้ในระดับเซิร์ฟเวอร์เนื่องจากไม่เฉพาะเจาะจงกับ IE ฉันหมายถึงถ้าทรัพยากรนั้นไม่ควรแคชให้ทำบนเซิร์ฟเวอร์ (สิ่งนี้ไม่เกี่ยวข้องกับเบราว์เซอร์ที่ใช้มันเป็นเรื่องที่น่าสนใจสำหรับทรัพยากร)

ตัวอย่างเช่นในจาวาที่มี JAX-RS ทำได้โดยทางโปรแกรมสำหรับ JAX-RS v1 หรือ declativlyสำหรับ JAX-RS v2

ฉันแน่ใจว่าทุกคนจะเข้าใจวิธีการใช้งาน


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

ผมอย่างเห็นนี้จะต้องเป็นวิธีการที่เหมาะสม
smnbbrv

1

นี่เป็นเรื่องเก่าไปหน่อย แต่: โซลูชันที่ล้าสมัยแล้ว ปล่อยให้เซิร์ฟเวอร์จัดการกับแคชหรือไม่แคช (ในการตอบกลับ) วิธีเดียวที่จะรับประกันว่าไม่มีการแคช (คิดเกี่ยวกับเวอร์ชันใหม่ในการผลิต) คือการเปลี่ยนไฟล์ js หรือ css ด้วยหมายเลขเวอร์ชั่น ฉันทำสิ่งนี้กับ webpack


1

นอกจากนี้คุณสามารถลองใน servce ของคุณเพื่อตั้งค่าส่วนหัวเช่น:

...
นำเข้า {Injectable} จาก "@ angular / core";
นำเข้า {HttpClient, HttpHeaders, HttpParams} จาก "@ angular / common / http";
...
 @Injectable ()
ส่งออกระดับ MyService {

    ส่วนหัวส่วนตัว: HttpHeaders;


    ตัวสร้าง (ส่วนตัว http: HttpClient .. ) 
    {


        this.headers = ใหม่ HttpHeaders ()
                    .append ("ประเภทเนื้อหา", "แอปพลิเคชัน / json")
                    .append ("ยอมรับ", "แอปพลิเคชัน / json")
                    .append ("LanguageCulture", this.headersLanguage)
                    .append ("การควบคุมแคช", "ไม่มีแคช")
                    .append ("Pragma", "no-cache")                   
    }
}
....


0

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

  1. ผนวกข้อมูลต่อไปนี้ด้วย URL คำขอบริการ http ของคุณ

// ก่อนหน้า (ออกครั้งเดียว)

this.httpService.get (this.serviceUrl + "/eAMobileService.svc/ValidateEngagmentName/" + engagementName, {})

// หลังจาก (ทำงานได้ดี)

this.httpService.get (this.serviceUrl + "/eAMobileService.svc/ValidateEngagmentName/" + EngagementName + "? DateTime =" + วันที่ใหม่ (). getTime () + '', {แคช: false})

  1. ปิดการใช้งานแคชสำหรับโมดูลทั้งหมด: -

$ httpProvider.defaults.headers.common ['Pragma'] = 'ไม่มีแคช';


0
meta http-equiv="Cache-Control" content="no-cache"

ฉันเพิ่งเพิ่มสิ่งนี้ลงในมุมมองและเริ่มทำงานกับ IE ยืนยันการทำงานกับ Angular 2


0

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

    let c=new Date().getTime();
    $http.get('url?d='+c)

-2

ลองสิ่งนี้มันใช้งานได้สำหรับฉันในกรณีที่คล้ายกัน: -

$http.get("your api url", {
headers: {
    'If-Modified-Since': '0',
    "Pragma": "no-cache",
    "Expires": -1,
    "Cache-Control": "no-cache, no-store, must-revalidate"
 }
})
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.