Vấn đề bộ nhớ đệm góc cạnh cho $ http


251

Tất cả các cuộc gọi ajax được gửi từ IE đều được Angular lưu vào bộ nhớ cache và tôi nhận được một 304 responsecuộc gọi cho tất cả các cuộc gọi tiếp theo. Mặc dù yêu cầu là như nhau, nhưng phản hồi sẽ không giống nhau trong trường hợp của tôi. Tôi muốn tắt bộ đệm này. Tôi đã thử thêm cache attribute$ http.get nhưng vẫn không được. Làm thế nào vấn đề này có thể được giải quyết?

Câu trả lời:


439

Thay vì vô hiệu hóa bộ đệm ẩn cho mỗi yêu cầu GET, tôi vô hiệu hóa nó trên toàn cầu trong $ 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
Các If-Modified-Sincelàm cho tiêu đề IIS + ném iisnode 400 Yêu cầu Xấu cho mỗi tập tin html nạp thông qua ngIncludengView. Mặc dù vậy, hai tiêu đề sau đã khắc phục sự cố cho tôi (Tôi đã lấy chúng từ Chrome, không có vấn đề về bộ nhớ đệm): $httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache'; $httpProvider.defaults.headers.get['Pragma'] = 'no-cache';
Langdon

4
Theo tôi, câu trả lời này nên được đánh dấu là câu trả lời, trong khi giải pháp do Martin cung cấp không hoạt động, đó là một vụ hack hơn là một sửa chữa thực tế.
Robba

4
Điều này hoạt động cho các yêu cầu GET cục bộ của tôi, nhưng nó đã gây ra một yêu cầu CORS mà tôi đang thực hiện để bắt đầu sử dụng phương thức TÙY CHỌN thay vì phương thức GET. Máy chủ của bên thứ 3 không hỗ trợ phương thức TÙY CHỌN, vì vậy cách giải quyết của tôi là sử dụng jQuery.get () để thực hiện yêu cầu đó và sử dụng $ scope.apply () trong trình xử lý phản hồi.
Ben

13
Việc sử dụng If-Modified-Since = "0"tiêu đề phá vỡ Tomcat (Vấn đề với phân tích ngày tiêu đề, vì RFC0 không có giá trị hợp lệ ). Đã sửa lỗi sử dụng giá trị thay thế. Mon, 26 Jul 1997 05:00:00 GMT
lopisan

6
Tôi đã không sử dụng tiêu đề "If-Modified-Because" và nó hoạt động mà không có điều đó. Chỉ cần hai cái còn lại là cần thiết.
Michael Mahony

69

Bạn có thể nối thêm một chuỗi truy vấn duy nhất (tôi tin rằng đây là những gì jQuery làm với tùy chọn cache: false) cho yêu cầu.

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

Một giải pháp có lẽ tốt hơn là nếu bạn có quyền truy cập vào máy chủ, thì bạn có thể đảm bảo rằng các tiêu đề cần thiết được đặt để ngăn chặn bộ đệm. Nếu bạn đang sử dụng ASP.NET MVC câu trả lời này có thể giúp đỡ.


2
$http.get(url+ "?"+new Date().toString())chỉ là một đại diện khác, không sử dụng tham số mà thêm nó vào chuỗi truy vấn.
Davut Gürbüz

28

bạn có thể thêm một thiết bị đánh chặn.

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;
               }
           };
    });

bạn nên xóa các dòng console.log sau khi xác minh.


Và bạn nên sử dụng $logtrong trường hợp bạn quên lấy chúng ra.
Carl G

2
Tôi đang gặp vấn đề nghiêm trọng về bộ nhớ đệm trong IE, dẫn đến một trang trống, vì các phần quan trọng đã không thực thi. Sử dụng các thiết bị đánh chặn có đạo cụ đã giải quyết vấn đề này! +1
raoulinski

Tôi nghĩ rằng đây là cách tiếp cận tốt nhất, vì nó tránh được các vấn đề với hành vi của CORS và IE trong việc kích hoạt yêu cầu preflight nếu bạn thêm các tiêu đề bổ sung. Đây dường như là phương pháp an toàn nhất để không gặp phải các vấn đề khác
chrismarx

@dilip pattnaik: - Tại sao vấn đề này xảy ra với góc và tức là?
MiHawk

14

Tôi chỉ cần thêm ba thẻ meta vào index.html trong dự án góc và vấn đề bộ đệm đã được giải quyết trên 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
Chúng tôi đã có các thẻ meta đó trong index.htmlkhi chúng tôi nhận thấy IE11 đang lưu các yêu cầu AJAX: / ​​Nhưng cấu hình $httpProvidernhư trong các câu trả lời khác hoạt động tốt.
walen

14

Sao chép câu trả lời của tôi trong một chủ đề khác .

Đối với Angular 2 và mới hơn , cách dễ nhất để thêm no-cachetiêu đề bằng cách ghi đè 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'
    });
}

Và tham khảo nó trong mô-đun của bạn:

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

Đó có phải là những tiêu đề cho phản hồi của máy chủ, không phải cho yêu cầu của trình duyệt không? (Tôi có thể tưởng tượng người ta có thể thiết lập If-Modified-Sincemột ngày nào đó trong quá khứ bằng phương pháp trên.)
Arjan

@Vitaliy: - Tại sao vấn đề này xảy ra với góc và tức là?
MiHawk

Cách tiếp cận của bạn sẽ loại bỏ bất kỳ tiêu đề tùy chỉnh đã có. Do đó, hãy làm như sau thay vì tạo một đối tượng Header mới. 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

Người được bảo đảm mà tôi đã làm việc là một cái gì đó dọc theo những dòng này:

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";
}]);

Tôi đã kết hợp 2 trong những giải pháp nêu trên để đảm bảo việc sử dụng đúng cho tất cả các phương pháp, nhưng bạn có thể thay thế commonbằng gethoặc phương pháp ví dụ khác put, post, deleteđể làm cho công việc này đối với trường hợp khác nhau.


bạn có thể cho tôi biết nơi bạn đã thêm mã này vào tệp angular.js không? dòng gì #?
JonathanScialpi

@JonathanScialpi Tôi đã cập nhật nó để hiển thị nơi tôi có thể đặt nó. Trường hợp nó nằm trong chức năng ẩn danh không nên quan trọng.
marksyzm

@markyzm bạn có thể nói cho tôi biết ý nghĩa của dòng này là gì khôngif (!$httpProvider.defaults.headers.get) { $httpProvider.defaults.headers.common = {}; }
Monojit Sarkar

@MonojitSarkar Ah, được cho là headers.common trong câu lệnh if, cảm ơn vì con trỏ đó
marksyzm

1
["If-Modified-Since"] = "0"là bất hợp pháp và với việc tạo một Yêu cầu xấu ở một số mặt sau. nó nên là một ngày
jenson-button-event

8

Dòng này chỉ giúp tôi (Angular 1.4.8):

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

CẬP NHẬT: Vấn đề là IE11 không lưu bộ nhớ cache tích cực. Khi tôi đang tìm hiểu về Fiddler, tôi nhận thấy rằng trong các chế độ F12, các yêu cầu đang gửi "Pragma = no-cache" và điểm cuối được yêu cầu mỗi khi tôi truy cập một trang. Nhưng ở chế độ bình thường, điểm cuối chỉ được yêu cầu một lần vào lần đầu tiên khi tôi truy cập trang.


1
Chỉ cần FYI, câu trả lời này đã gây ra sự cố CORS khi yêu cầu các tệp từ bộ lưu trữ blob của Azure, khó theo dõi nhưng cuối cùng đã tìm ra đây là nguyên nhân. Xóa tiêu đề pragma đã khắc phục sự cố CORS của tôi (nhưng lại gây ra sự cố bộ đệm IE).
keithl8041

7

Để tránh bộ đệm, một tùy chọn là cung cấp URL khác nhau cho cùng một tài nguyên hoặc dữ liệu. Để tạo URL khác nhau, bạn có thể thêm một chuỗi truy vấn ngẫu nhiên vào cuối URL. Kỹ thuật này hoạt động cho các yêu cầu ajax kiểu JQuery, Angular hoặc loại khác.

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

6

Tôi nhận được nó giải quyết nối thêm datetime như một số ngẫu nhiên:

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

: - Tại sao vấn đề này xảy ra với góc và tức là?
MiHawk

4

Giải pháp ở trên sẽ hoạt động (làm cho url duy nhất bằng cách thêm vào chuỗi truy vấn một tham số mới) nhưng tôi thích giải pháp đề xuất [ở đây]: Cách tốt hơn để ngăn chặn bộ đệm IE trong AngularJS?, xử lý việc này ở cấp máy chủ vì nó không dành riêng cho IE. Ý tôi là, nếu tài nguyên đó không nên được lưu vào bộ nhớ cache, hãy thực hiện nó trên máy chủ (điều này chẳng liên quan gì đến trình duyệt được sử dụng; nó không phù hợp với tài nguyên).

Ví dụ, trong java với JAX-RS, hãy lập trình cho JAX-RS v1 hoặc theo cách rõ ràng cho JAX-RS v2.

Tôi chắc chắn bất cứ ai cũng sẽ tìm ra cách để làm điều đó


1
Mặc dù nó có thể được xây dựng, đây là cách làm đúng đắn. Phía khách hàng không nên chọn những gì để lưu trữ hay không, nhưng đó phải là máy chủ sẽ cho khách hàng biết những gì cần được lưu trữ hay không.
Archimedes Trajano

Tôi hoàn toàn đồng ý, đây phải là một cách thích hợp
smnbbrv

1

Đây là một chút để cũ nhưng: Giải pháp như đã lỗi thời. Hãy để máy chủ xử lý bộ đệm hoặc không lưu bộ đệm (trong phản hồi). Cách duy nhất để đảm bảo không có bộ nhớ đệm (nghĩ về các phiên bản mới trong sản xuất) là thay đổi tệp js hoặc css bằng số phiên bản. Tôi làm điều này với webpack.


1

ngoài ra, bạn có thể thử trong dịch vụ của mình để đặt các tiêu đề như ví dụ:

...
nhập {tiêm} từ "@ angular / core";
nhập {httpClient, HttpHeaders, HttpParams} từ "@ angular / common / http";
...
 @Injectable ()
lớp xuất khẩu MyService {

    tiêu đề riêng: httpHeaders;


    hàm tạo (http riêng tư: httpClient ..) 
    {


        this .headers = new httpHeaders ()
                    .append ("Loại nội dung", "ứng dụng / json")
                    .append ("Chấp nhận", "ứng dụng / json")
                    .append ("LanguageCARM", this.headersL Language)
                    .append ("Kiểm soát bộ đệm", "không có bộ đệm")
                    .append ("Thực dụng", "không có bộ đệm")                   
    }
}
....


0

Sự cố này là do sự cố bộ đệm IE như bạn đã nói, bạn có thể kiểm tra nó trong chế độ gỡ lỗi IE bằng cách nhấn f12 (điều này sẽ hoạt động tốt trong chế độ gỡ lỗi) .IE sẽ không lấy dữ liệu máy chủ trong mỗi lần gọi trang. dữ liệu từ bộ đệm. Để vô hiệu hóa điều này, hãy làm một trong những điều sau đây:

  1. nối các phần sau với url yêu cầu dịch vụ http của bạn

// Trước (ban hành một)

this .httpService.get (this.serviceUrl + "/eAMobileService.svc/ValidateEngagmentName/" + Đính hôn, {})

// Sau (hoạt động tốt)

this.

  1. vô hiệu hóa bộ đệm cho toàn bộ Mô-đun: -

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


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

Tôi vừa thêm cái này vào View và nó bắt đầu hoạt động trên IE. Xác nhận làm việc trên Angular 2.


0

Một tùy chọn là sử dụng cách tiếp cận đơn giản là thêm Dấu thời gian với mỗi yêu cầu không cần xóa bộ đệm.

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

-2

Hãy thử điều này, nó đã làm việc cho tôi trong một trường hợp tương tự: -

$http.get("your api url", {
headers: {
    'If-Modified-Since': '0',
    "Pragma": "no-cache",
    "Expires": -1,
    "Cache-Control": "no-cache, no-store, must-revalidate"
 }
})
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.