कोणीय 2 साइट पर ब्राउज़र कैश को कैसे रोकें?


104

वर्तमान में हम एक नए प्रोजेक्ट पर काम कर रहे हैं जिसमें नियमित अपडेट है जो हमारे ग्राहकों द्वारा दैनिक उपयोग किया जा रहा है। यह परियोजना कोणीय 2 का उपयोग करके विकसित की जा रही है और हम कैश के मुद्दों का सामना कर रहे हैं, यही कारण है कि हमारे ग्राहक अपनी मशीनों पर नवीनतम बदलाव नहीं देख रहे हैं।

मुख्य रूप से js फाइलों के लिए html / css फाइलें ज्यादा परेशानी दिए बिना ठीक से अपडेट होने लगती हैं।


2
बहुत अच्छा सवाल है। मेरी भी यही समस्या है। इस समस्या को हल करने का सबसे अच्छा तरीका क्या है? क्या यह कोणीय 2 अनुप्रयोग को प्रकाशित करने के लिए गल्प या किसी भी समान उपकरण के साथ संभव है?
जंप 4791

2
@ jump4791 सबसे अच्छा तरीका वेबपैक का उपयोग करना और उत्पादन सेटिंग्स का उपयोग करके परियोजना को संकलित करना है। मैं वर्तमान में इस रेपो का उपयोग कर रहा हूं, बस चरणों का पालन करें और आपको अच्छा होना चाहिए: github.com/AngularClass/angular2-webpack-starter
Rikku121

मेरा भी यही मुद्दा है।
जिग्लर

3
मुझे पता है कि यह एक पुराना प्रश्न है लेकिन मैं इस समाधान को जोड़ना चाहता था, जो भी इस पर होता है। निर्माण के साथ ng build, -prodटैग जोड़ने से उत्पन्न फ़ाइल नामों में एक हैश जुड़ जाता है। यह सब कुछ है, लेकिन के पुनः लोड मजबूर करता index.htmlइस github पोस्ट को पुनः लोड करने के लिए कुछ संकेत मिले।
Tiz

2
index.html मूल कारण है। क्योंकि इसमें हैशकोड नहीं है, जब इसे कैश किया जाता है, तो बाकी सब कुछ कैश से उपयोग किया जाता है।
फियोना

जवाबों:


178

कोणीय-क्लि बिल्ड कमांड के --output-hashingलिए एक ध्वज प्रदान करके इसे हल करता है (संस्करण 6/7, बाद के संस्करणों के लिए यहां देखें )। उदाहरण का उपयोग:

ng build --output-hashing=all

बंडलिंग और ट्री-शेकिंग कुछ विवरण और संदर्भ प्रदान करता है। चल रहा है ng help build, झंडे के दस्तावेज:

--output-hashing=none|all|media|bundles (String)

Define the output filename cache-busting hashing mode.
aliases: -oh <value>, --outputHashing <value>

हालांकि यह केवल कोणीय-क्ली के उपयोगकर्ताओं के लिए लागू है , यह शानदार ढंग से काम करता है और इसके लिए किसी कोड परिवर्तन या अतिरिक्त टूलिंग की आवश्यकता नहीं होती है।

अपडेट करें

टिप्पणियों की एक संख्या है काम आते हुए और सही ढंग से कहा कि इस उत्तर के लिए एक हैश कहते हैं .jsफ़ाइलों लेकिन के लिए कुछ नहीं करता है index.html। इसलिए यह पूरी तरह से संभव है कि कैश बस्ट index.htmlहोने के बाद भी ng buildकैश की कमी बनी रहती है .js

इस बिंदु पर, हम सभी ब्राउज़रों के बीच वेब पेज कैशिंग को कैसे नियंत्रित करेंगे , इसके बारे में बताऊंगा।


14
यह ऐसा करने का उचित तरीका है और चयनित उत्तर होना चाहिए!
jonesy827

1
यह हमारे ऐप के लिए काम नहीं आया। यह बहुत खराब है एक स्ट्रिंग स्ट्रिंग पैरामीटर के साथ टेम्पलेट
यूआरएल

8
यदि आपका index.html ब्राउज़र द्वारा कैश नहीं किया गया है, तो यह काम नहीं करेगा, इसलिए आपके जावास्क्रिप्ट संसाधनों के लिए नए हैशेड नाम नहीं देखेंगे। मुझे लगता है कि यह इस और @Rossco के जवाब का एक मतलब होगा। यह HTTP हेडर भेजे जाने के साथ इसे संगत बनाने के लिए भी समझ में आता है।
स्ट्राबा

2
@stryba यही कारण है कि html कैशिंग को अलग तरह से संभाला जाना चाहिए। आपको Cache-Control, Pragma और Expire रिस्पॉन्स हेडर को निर्दिष्ट करना चाहिए ताकि कोई कैशिंग न हो। यदि आप एक बैकएंड फ्रेमवर्क का उपयोग कर रहे हैं तो यह आसान है, लेकिन मेरा मानना ​​है कि आप इसे अपाचे के लिए .htaccess फ़ाइलों में भी संभाल सकते हैं (आईडीके कि यह नैग्नेक्स में कैसे काम करता है)।
18

3
यह उत्तर js फ़ाइलों में एक हैश जोड़ता है, जो बहुत अच्छा है। लेकिन जैसा कि स्ट्रीबा ने कहा, आपको यह भी सुनिश्चित करना होगा कि index.html को कैश नहीं किया गया है। आपको html मेटा टैग के साथ ऐसा नहीं करना चाहिए, लेकिन प्रतिक्रिया हेडर कैश-कंट्रोल के साथ: नो-कैश (या अधिक फैंसी कैशिंग रणनीतियों के लिए अन्य हेडर)।
Noppey

34

इसे करने का एक तरीका मिला, बस अपने घटकों को लोड करने के लिए एक querystring जोड़ें, जैसे:

@Component({
  selector: 'some-component',
  templateUrl: `./app/component/stuff/component.html?v=${new Date().getTime()}`,
  styleUrls: [`./app/component/stuff/component.css?v=${new Date().getTime()}`]
})

यह क्लाइंट को ब्राउज़र की बजाय टेम्पलेट की सर्वर कॉपी लोड करने के लिए मजबूर करना चाहिए। यदि आप एक निश्चित अवधि के बाद ही इसे रिफ्रेश करना चाहते हैं, तो आप इसके बजाय इस ISOString का उपयोग कर सकते हैं:

new Date().toISOString() //2016-09-24T00:43:21.584Z

और कुछ पात्रों को प्रतिस्थापित करना ताकि यह केवल उदाहरण के लिए एक घंटे के बाद बदल जाए:

new Date().toISOString().substr(0,13) //2016-09-24T00

उम्मीद है की यह मदद करेगा


3
इसलिए मेरा कार्यान्वयन वास्तव में काम नहीं कर रहा था। कैशिंग एक अजीब मुद्दा है। कभी काम करता है और कभी नहीं। ओह, आंतरायिक मुद्दों की सुंदरता। इसलिए मैंने वास्तव में आपके उत्तर को इस तरह से अनुकूलित किया:templateUrl: './app/shared/menu/menu.html?v=' + Math.random()
रॉस्को डे

मुझे अपने टेम्पलेट के लिए 404 मिल रहे हैं। उदाहरण के लिए: GET लोकलहोस्ट: 8080 / app.component.html /? V = 0.0.1-अल्फा 404 (नहीं मिला) कोई विचार क्यों?
शेनबो

@ Rikku121 नहीं यह नहीं है। यह वास्तव में यूआरएल में / के बिना है। मैंने गलती से इसे जोड़ा हो सकता है जब मैं टिप्पणी पोस्ट करता हूं
शेनबो

14
जब आप कोड में बदलाव नहीं कर रहे हैं तब भी जब आप हर बार कैश का भंडाफोड़ कर रहे हैं तो कैशिंग का क्या मतलब है?
अपूर्वा कमलापुरी

1
एनजी बिल्ड-aot --build-optimizer = true --base-href = / <url> / त्रुटि देता है। संसाधन का समाधान नहीं कर रहा है। getTime ()}
प्रांजल

23

प्रत्येक HTML टेम्पलेट में मैं शीर्ष पर केवल निम्नलिखित मेटा टैग जोड़ता हूं:

<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">

मेरी समझ में प्रत्येक टेम्प्लेट स्वतंत्र है, इसलिए यह मेटा में कोई कैशिंग नियम सेटअप अनुक्रमणिका फ़ाइल में इनहेरिट नहीं करता है।


4
हमने पिछले कुछ समय से वेबपैक पर स्विच किया है और यह हमारे कोणीय ऐप को नष्ट करने वाले कैश का ध्यान रखता है। हालांकि अपने समाधान काम करता है यह जानना अच्छा है। धन्यवाद
Rikku121

यह मेरे लिए भी किया
iniravpatel

4

@ जैक के उत्तर और @ रेनियरबिट के उत्तर का संयोजन चाल करना चाहिए।

एनजी बिल्ड फ्लैग को --आउटपुट-हैशिंग के लिए सेट करें:

ng build --output-hashing=all

फिर इस वर्ग को सेवा में या अपने app.moudle में जोड़ें

@Injectable()
export class NoCacheHeadersInterceptor implements HttpInterceptor {
    intercept(req: HttpRequest<any>, next: HttpHandler) {
        const authReq = req.clone({
            setHeaders: {
                'Cache-Control': 'no-cache',
                 Pragma: 'no-cache'
            }
        });
        return next.handle(authReq);    
    }
}

तो आप app.module में अपने प्रदाताओं में यह जोड़ें:

providers: [
  ... // other providers
  {
    provide: HTTP_INTERCEPTORS,
    useClass: NoCacheHeadersInterceptor,
    multi: true
  },
  ... // other providers
]

यह ग्राहक मशीनों के लिए लाइव साइटों पर कैशिंग मुद्दों को रोकना चाहिए


3

मैं इसी तरह के मुद्दे के साथ था। Html ब्राउज़र द्वारा कैश किया जा रहा है या मध्य cdn / proxies (F5 आपकी मदद नहीं करेगा) द्वारा अधिक मुश्किल है।

मैंने एक ऐसे समाधान की तलाश की जो 100% सत्यापित करता है कि क्लाइंट के पास नवीनतम index.html संस्करण है, सौभाग्य से मुझे हेनरिक पेनेटरी द्वारा यह समाधान मिला है:

https://blog.nodeswat.com/automagic-reload-for-clients-after-deploy-with-angular-4-8440c9fdd96c

समाधान उस मामले को भी हल करता है जहां ग्राहक दिनों के लिए ब्राउज़र के साथ खुला रहता है, ग्राहक अंतराल पर अपडेट की जांच करता है और अगर नया संस्करण डिप्लॉयड फिर से लोड करता है।

समाधान थोड़ा मुश्किल है लेकिन एक आकर्षण की तरह काम करता है:

  • इस तथ्य का उपयोग करें कि ng cli -- prodउनमें से एक के साथ हैशेड फ़ाइलों का उत्पादन होता है जिन्हें मुख्य कहा जाता है। [हैश] .js
  • एक संस्करण.जसन फ़ाइल बनाएँ जिसमें वह हैश हो
  • एक कोणीय सेवा बनाएँ वर्जनचेक सर्विस जो कि वर्जन.जॉन को चेक करती है और जरूरत पड़ने पर पुनः लोड करती है।
  • ध्यान दें कि तैनाती के बाद चलने वाली एक js स्क्रिप्ट आपके लिए दोनों version.json और कोणीय सेवा में हैश की जगह लेती है, इसलिए किसी मैनुअल काम की आवश्यकता नहीं है, लेकिन पोस्ट-बिल्ड.js को चलाना

चूँकि हेनरिक पीनर का समाधान कोणीय 4 के लिए था, इसलिए इसमें कुछ छोटे बदलाव हुए, मैं यहाँ निश्चित स्क्रिप्ट भी रखता हूँ:

वर्जनचेक सर्विस:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class VersionCheckService {
    // this will be replaced by actual hash post-build.js
    private currentHash = '{{POST_BUILD_ENTERS_HASH_HERE}}';

    constructor(private http: HttpClient) {}

    /**
     * Checks in every set frequency the version of frontend application
     * @param url
     * @param {number} frequency - in milliseconds, defaults to 30 minutes
     */
    public initVersionCheck(url, frequency = 1000 * 60 * 30) {
        //check for first time
        this.checkVersion(url); 

        setInterval(() => {
            this.checkVersion(url);
        }, frequency);
    }

    /**
     * Will do the call and check if the hash has changed or not
     * @param url
     */
    private checkVersion(url) {
        // timestamp these requests to invalidate caches
        this.http.get(url + '?t=' + new Date().getTime())
            .subscribe(
                (response: any) => {
                    const hash = response.hash;
                    const hashChanged = this.hasHashChanged(this.currentHash, hash);

                    // If new version, do something
                    if (hashChanged) {
                        // ENTER YOUR CODE TO DO SOMETHING UPON VERSION CHANGE
                        // for an example: location.reload();
                        // or to ensure cdn miss: window.location.replace(window.location.href + '?rand=' + Math.random());
                    }
                    // store the new hash so we wouldn't trigger versionChange again
                    // only necessary in case you did not force refresh
                    this.currentHash = hash;
                },
                (err) => {
                    console.error(err, 'Could not get version');
                }
            );
    }

    /**
     * Checks if hash has changed.
     * This file has the JS hash, if it is a different one than in the version.json
     * we are dealing with version change
     * @param currentHash
     * @param newHash
     * @returns {boolean}
     */
    private hasHashChanged(currentHash, newHash) {
        if (!currentHash || currentHash === '{{POST_BUILD_ENTERS_HASH_HERE}}') {
            return false;
        }

        return currentHash !== newHash;
    }
}

मुख्य AppComponent में परिवर्तन:

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
    constructor(private versionCheckService: VersionCheckService) {

    }

    ngOnInit() {
        console.log('AppComponent.ngOnInit() environment.versionCheckUrl=' + environment.versionCheckUrl);
        if (environment.versionCheckUrl) {
            this.versionCheckService.initVersionCheck(environment.versionCheckUrl);
        }
    }

}

पोस्ट-बिल्ड स्क्रिप्ट जो जादू बनाती है, पोस्ट-बिल्ड.js:

const path = require('path');
const fs = require('fs');
const util = require('util');

// get application version from package.json
const appVersion = require('../package.json').version;

// promisify core API's
const readDir = util.promisify(fs.readdir);
const writeFile = util.promisify(fs.writeFile);
const readFile = util.promisify(fs.readFile);

console.log('\nRunning post-build tasks');

// our version.json will be in the dist folder
const versionFilePath = path.join(__dirname + '/../dist/version.json');

let mainHash = '';
let mainBundleFile = '';

// RegExp to find main.bundle.js, even if it doesn't include a hash in it's name (dev build)
let mainBundleRegexp = /^main.?([a-z0-9]*)?.js$/;

// read the dist folder files and find the one we're looking for
readDir(path.join(__dirname, '../dist/'))
  .then(files => {
    mainBundleFile = files.find(f => mainBundleRegexp.test(f));

    if (mainBundleFile) {
      let matchHash = mainBundleFile.match(mainBundleRegexp);

      // if it has a hash in it's name, mark it down
      if (matchHash.length > 1 && !!matchHash[1]) {
        mainHash = matchHash[1];
      }
    }

    console.log(`Writing version and hash to ${versionFilePath}`);

    // write current version and hash into the version.json file
    const src = `{"version": "${appVersion}", "hash": "${mainHash}"}`;
    return writeFile(versionFilePath, src);
  }).then(() => {
    // main bundle file not found, dev build?
    if (!mainBundleFile) {
      return;
    }

    console.log(`Replacing hash in the ${mainBundleFile}`);

    // replace hash placeholder in our main.js file so the code knows it's current hash
    const mainFilepath = path.join(__dirname, '../dist/', mainBundleFile);
    return readFile(mainFilepath, 'utf8')
      .then(mainFileData => {
        const replacedFile = mainFileData.replace('{{POST_BUILD_ENTERS_HASH_HERE}}', mainHash);
        return writeFile(mainFilepath, replacedFile);
      });
  }).catch(err => {
    console.log('Error with post build:', err);
  });

बस (नया) बिल्ड फ़ोल्डर में स्क्रिप्ट node ./build/post-build.jsरखें डिस्ट फ़ोल्डर का उपयोग करके बिल्डिंग का उपयोग करने के बाद स्क्रिप्ट चलाएंng build --prod


1

आप HTTP हेडर के साथ क्लाइंट कैश को नियंत्रित कर सकते हैं। यह किसी भी वेब फ्रेमवर्क में काम करता है।

आप इन शीर्षकों को निर्देश सेट कर सकते हैं कि कैसे और कब सक्षम करें |

  • Cache-Control
  • Surrogate-Control
  • Expires
  • ETag (बहुत अच्छा)
  • Pragma (यदि आप पुराने ब्राउज़रों का समर्थन करना चाहते हैं)

सभी कंप्यूटर सिस्टम में अच्छा कैशिंग अच्छा है, लेकिन बहुत जटिल है । अधिक जानकारी के लिए https://helmetjs.github.io/docs/nocache/#the-headers पर एक नज़र डालें ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.