অ্যাঙ্গুলার 2 সাইটে ব্রাউজার ক্যাশে কীভাবে প্রতিরোধ করবেন?


108

আমরা বর্তমানে নিয়মিত আপডেট সহ একটি নতুন প্রকল্পে কাজ করছি যা আমাদের ক্লায়েন্টদের একজন প্রতিদিন ব্যবহার করে চলেছে। এই প্রকল্পটি কৌণিক 2 ব্যবহার করে বিকাশ করা হচ্ছে এবং আমরা ক্যাশে সমস্যার মুখোমুখি হচ্ছি, তা হচ্ছে আমাদের ক্লায়েন্টরা তাদের মেশিনে সর্বশেষ পরিবর্তনগুলি দেখছেন না seeing

মূলত জেএস ফাইলের জন্য এইচটিএমএল / সিএসএস ফাইলগুলি খুব বেশি সমস্যা না দিয়েই সঠিকভাবে আপডেট হয়ে গেছে বলে মনে হয়।


4
খুব ভাল প্রশ্ন। আমি একই সমস্যা আছে। এই সমস্যাটি সমাধানের সর্বোত্তম উপায় কী? কৌণিক 2 অ্যাপ্লিকেশন প্রকাশের জন্য ঝলক বা অনুরূপ কোনও সরঞ্জাম দিয়ে এটি কি সম্ভব?
জাম্প 4791

4
@ jump4791 সর্বোত্তম উপায় হ'ল ওয়েবপ্যাক ব্যবহার করা এবং প্রোডাকশন সেটিংস ব্যবহার করে প্রকল্পটি সংকলন করা। আমি বর্তমানে এই রেপো ব্যবহার করছি, কেবলমাত্র পদক্ষেপগুলি অনুসরণ করুন এবং আপনার ভাল হওয়া উচিত: github.com/AngularClass/angular2-webpack-starter
রিক্কু 121

আমারও একই সমস্যা আছে।
জিগ্লার

4
আমি জানি এটি একটি পুরানো প্রশ্ন তবে আমি যে সমাধান পেয়েছি তার জন্য আমি যে সমাধানটি পেয়েছি তা যুক্ত করতে চেয়েছিলাম। ng buildবিল্ড করার সাথে , -prodট্যাগ যুক্ত করা উত্পন্ন ফাইলের নামের সাথে একটি হ্যাশ যুক্ত করে । এটি সমস্ত কিছুর পুনরায় লোড করতে বাধ্য করে index.htmlএই গিথুব পোস্টে এটি পুনরায় লোড করার বিষয়ে কিছু ইঙ্গিত ছিল।
টিজ

4
index.html এর মূল কারণ। কারণ এতে হ্যাশকোড নেই, যখন এটি ক্যাশ করা হয় তখন সমস্ত কিছু ক্যাশে থেকে ব্যবহৃত হয়।
ফিয়োনা

উত্তর:


183

কৌণিক-ক্লিপ বিল্ড কমান্ডের --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

4
এটি আমাদের অ্যাপ্লিকেশনটির জন্য কাজ করে না। এটি খুব খারাপ যে কোনও প্রশ্নের স্ট্রিং প্যারামিটার সহ টেমপ্লেটটি
ইউআরএল সি এল এল-এর

8
আপনার সূচিপত্র। HTML ব্রাউজার দ্বারা ক্যাশে করা থাকলে এটি কাজ করবে না, সুতরাং আপনার জাভাস্ক্রিপ্ট সংস্থানগুলির জন্য নতুন হ্যাশ নামগুলি দেখতে পাবে না। আমি মনে করি এটির সাথে এর সমাধান এবং @ রোসকো দেওয়া উত্তরটি উপলব্ধি করবে। এটি প্রেরিত এইচটিটিপি শিরোনামগুলির সাথে এটি সামঞ্জস্য বানাতেও বোধগম্য হয়।
stryba

4
@ স্ট্রাইবা এ কারণেই এইচটিএমএল ক্যাচিংকে আলাদাভাবে পরিচালনা করা উচিত। আপনার ক্যাশে-নিয়ন্ত্রণ, প্রাগমা, এবং প্রতিক্রিয়া শিরোনামগুলি নির্দিষ্ট করা উচিত যাতে কোনও ক্যাচিং না ঘটে। আপনি যদি ব্যাকএন্ড কাঠামো ব্যবহার করছেন তবে এটি সহজ, তবে আমি বিশ্বাস করি আপনি এপাচি (hdaccess ফাইলগুলি যদিও এনজিঙ্কসে এটি কাজ করে) এর জন্য .htaccess ফাইলগুলিতেও এটি পরিচালনা করতে পারেন।
ওজজি দ্যজেন্ট

4
এই উত্তরটি js ফাইলগুলিতে একটি হ্যাশ যুক্ত করে, যা দুর্দান্ত। তবে স্ট্রাইবা যেমন বলেছিলেন, আপনাকেও নিশ্চিত করতে হবে যে সূচিপত্র। Html ক্যাশেড নয়। আপনার এইচটিএমএল মেটা ট্যাগগুলি দিয়ে করা উচিত নয়, তবে প্রতিক্রিয়া শিরোনাম ক্যাশে-নিয়ন্ত্রণের সাথে: নো-ক্যাশে (বা আরও অভিনব ক্যাশে কৌশলগুলির জন্য অন্যান্য শিরোনাম)।
নোপ্পি

35

এটি করার একটি উপায় খুঁজে পেয়েছেন, কেবল আপনার উপাদানগুলি লোড করতে একটি ক্যোরিস্ট্রিং যুক্ত করুন:

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

এটি ক্লায়েন্টকে ব্রাউজারের পরিবর্তে টেমপ্লেটের সার্ভারের অনুলিপি লোড করতে বাধ্য করবে। আপনি যদি একটি নির্দিষ্ট সময়ের পরে কেবল তা সতেজ করতে চান তবে আপনি পরিবর্তে এই আইএসওএসটারিং ব্যবহার করতে পারেন:

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

এবং কিছু অক্ষর বিশিষ্ট করা যাতে এটি কেবলমাত্র এক ঘন্টা পরে পরিবর্তিত হবে উদাহরণস্বরূপ:

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

আশাকরি এটা সাহায্য করবে


4
সুতরাং আমার বাস্তবায়ন আসলে কাজ শেষ হয়নি। ক্যাশিং একটি আজব বিষয়। কখনও কখনও কাজ করে এবং কখনও কখনও না। ওহ অন্তরীন সমস্যাগুলির সৌন্দর্য। সুতরাং আমি আসলে আপনার উত্তরটিকে যেমন রূপান্তরিত করেছি:templateUrl: './app/shared/menu/menu.html?v=' + Math.random()
রসকো

আমি আমার টেম্পলেট ইউআরএলগুলির জন্য 404 পাচ্ছি। উদাহরণস্বরূপ: GET লোকালহোস্ট: 8080 / app.componal.html /? V = 0.0.1-alpha 404 (পাওয়া যায়নি) কোনও ধারণা কেন?
শেনবো

@ Rikku121 না এটি হয় না। এটি আসলে / ইউআরএল ছাড়াই। মন্তব্যটি পোস্ট করার সময় আমি ঘটনাক্রমে এটিকে যুক্ত করে থাকতে পারি
শেনবো

15
কোড পরিবর্তন না হওয়া সত্ত্বেও আপনি যখন প্রতিবার ক্যাশে আবদ্ধ করছেন তখন ক্যাশে করার কী দরকার?
অপূর্ব কমলাপুরি

4
এনজি বিল্ড --aot - বিল্ড-অপ্টিমাইজার = সত্য --base-href = / <url> / ত্রুটি দেয় --- উত্স সমাধান করতে পারেনি / getTime ()}
Pranjal Successena

24

প্রতিটি এইচটিএমএল টেমপ্লেটে আমি কেবল নীচে নীচের মেটা ট্যাগ যুক্ত করেছি:

<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
আমরা এখন কিছু সময়ের জন্য ওয়েবপ্যাকে স্যুইচ করেছি এবং এটি আমাদের কৌণিক অ্যাপ্লিকেশনগুলিকে আবদ্ধকারী ক্যাশে যত্ন নেবে। যদিও আপনার সমাধানটি কাজ করে তা জেনে রাখা ভাল। ধন্যবাদ
রিক্কু 121

এটি আমার জন্যও করেছিল
ইনিরাভপেটেল

5

@ জ্যাকের উত্তর এবং @ রনিয়ারবিতের উত্তরগুলির সংমিশ্রণটি কৌশলটি করা উচিত।

আউটপুট-হ্যাশিংয়ের জন্য এনজি বিল্ড পতাকা সেট করুন:

ng build --output-hashing=all

তারপরে এই ক্লাসটি কোনও পরিষেবাতে বা আপনার মধ্যে যুক্ত করুন app.module

@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 বা মিডল সিডিএন / প্রক্সি দ্বারা আরও জটিল (এফ 5 আপনাকে সাহায্য করবে না) এর সাথে আমার একই সমস্যা ছিল।

আমি এমন একটি সমাধান খুঁজছিলাম যা 100% যাচাই করে যে ক্লায়েন্টটির সর্বশেষ সূচক html সংস্করণ রয়েছে, ভাগ্যক্রমে আমি হেনরিক পিনারের এই সমাধানটি পেয়েছি:

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

সমাধানটি সেই ক্ষেত্রেও সমাধান করে যেখানে ক্লায়েন্টটি ব্রাউজারের সাথে কয়েক দিন খোলা থাকে, ক্লায়েন্ট অন্তরগুলিতে আপডেটগুলি পরীক্ষা করে এবং নতুন সংস্করণ মোতায়েন হলে পুনরায় লোড করে।

সমাধানটি কিছুটা জটিল তবে একটি কবজির মতো কাজ করে:

  • ng cli -- prodতাদের মধ্যে প্রধান নামে পরিচিত হ্যাশ ফাইল তৈরি করে এমন তথ্য ব্যবহার করুন main [হ্যাশ] .js
  • একটি সংস্করণ.জসন ফাইল তৈরি করুন যাতে এতে হ্যাশ রয়েছে
  • একটি কৌণিক পরিষেবা সংস্করণচেক সার্ভিস তৈরি করুন যা version.json পরীক্ষা করে এবং প্রয়োজনে পুনরায় লোড করুন।
  • নোট করুন যে মোতায়েনের পরে চলমান একটি জেএস স্ক্রিপ্ট আপনার উভয় ভার্সন.জসন তৈরি করে এবং হ্যাশটি কৌণিক পরিষেবাতে প্রতিস্থাপন করে, সুতরাং কোনও ম্যানুয়াল কাজের প্রয়োজন নেই, তবে পোস্ট বিল্ড.জেএস চলছে running

হেনরিক পিনার সমাধান যেহেতু কৌণিক 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;
    }
}

প্রধান অ্যাপকোম্পোন্টে পরিবর্তন করুন:

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

}

পোস্ট-বিল্ড স্ক্রিপ্ট যা যাদু করে তোলে, পোস্ট-বিল্ড.জেএস:

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 আরও তথ্যের জন্য।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.