Angular 2 사이트에서 브라우저 캐시를 방지하는 방법은 무엇입니까?
우리는 현재 고객 중 한 명이 매일 정기적으로 업데이트하는 새로운 프로젝트를 진행하고 있습니다. 이 프로젝트는 angular 2를 사용하여 개발 중이며 캐시 문제에 직면 해 있습니다. 즉, 클라이언트가 컴퓨터에서 최신 변경 사항을 보지 못하고 있습니다.
주로 js 파일의 html / css 파일은 많은 문제를 일으키지 않고 제대로 업데이트되는 것 같습니다.
angular-cli--output-hashing
는 빌드 명령에 플래그를 제공하여이를 훌륭하게 해결합니다 . 사용 예 :
ng build --aot --output-hashing=all
Bundling & Tree-Shaking 은 몇 가지 세부 사항과 컨텍스트를 제공합니다. 를 실행 ng help build
하면 플래그가 문서화됩니다.
--output-hashing=none|all|media|bundles (String) Define the output filename cache-busting hashing mode.
aliases: -oh <value>, --outputHashing <value>
이것은 angular-cli 사용자에게만 적용되지만 훌륭하게 작동하며 코드 변경이나 추가 도구가 필요하지 않습니다.
이 작업을 수행하는 방법을 찾았 으면 다음과 같이 구성 요소를로드 할 쿼리 문자열을 추가하기 만하면됩니다.
@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
도움이 되었기를 바랍니다
각 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">
내 이해에서 각 템플릿은 독립형이므로 index.html 파일에 설정된 캐싱 규칙이없는 메타를 상속하지 않습니다.
index.html이 브라우저에 의해 캐시되거나 중간 cdn / 프록시에 의해 더 까다로워지는 것과 비슷한 문제가있었습니다 (F5는 도움이되지 않습니다).
클라이언트가 최신 index.html 버전을 가지고 있는지 100 % 확인하는 솔루션을 찾았습니다. 다행히 Henrik Peinar가이 솔루션을 찾았습니다.
https://blog.nodeswat.com/automagic-reload-for-clients-after-deploy-with-angular-4-8440c9fdd96c
이 솔루션은 클라이언트가 브라우저를 며칠 동안 열어 둔 채로있는 경우도 해결하고, 클라이언트는 주기적으로 업데이트를 확인하고 최신 버전이 배포 된 경우 다시로드합니다.
솔루션은 약간 까다 롭지 만 매력적으로 작동합니다.
ng cli -- prod
main. [hash] .js 중 하나와 함께 해시 파일 을 생성 한다는 사실을 사용하십시오 .- 해당 해시를 포함하는 version.json 파일을 만듭니다.
- version.json을 확인하고 필요한 경우 다시로드하는 각도 서비스 VersionCheckService를 만듭니다.
- 배포 후 실행되는 js 스크립트는 version.json을 생성하고 각도 서비스의 해시를 대체하므로 수동 작업이 필요하지 않지만 post-build.js를 실행합니다.
Henrik Peinar 솔루션은 angular 4 용이므로 약간의 변경이 있었으므로 여기에 고정 스크립트도 배치합니다.
VersionCheckService :
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);
}
}
}
마법을 만드는 포스트 빌드 스크립트, post-build.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
dist 폴더를 빌드 한 후 사용하여 스크립트를 실행하십시오.ng build --prod
HTTP 헤더로 클라이언트 캐시를 제어 할 수 있습니다. 이것은 모든 웹 프레임 워크에서 작동합니다.
이러한 헤더의 지시문을 설정하여 캐시를 활성화하는 방법과시기를 세밀하게 제어 할 수 있습니다.
Cache-Control
Surrogate-Control
Expires
ETag
(아주 좋은 것)Pragma
(이전 브라우저를 지원하려는 경우)
Good caching is good, but very complex, in all computer systems. Take a look at https://helmetjs.github.io/docs/nocache/#the-headers for more information.
참고URL : https://stackoverflow.com/questions/39647810/how-to-prevent-browser-cache-on-angular-2-site
'IT TIP' 카테고리의 다른 글
Rails 4 before_action, 호출 된 메소드에 매개 변수 전달 (0) | 2020.10.20 |
---|---|
Android AppCompat 21 Elevation (0) | 2020.10.20 |
문자열 변수의 N 번째 단어 (0) | 2020.10.20 |
iPhone 중지 performSelector 취소 방법 (0) | 2020.10.20 |
Objective-C 문서 생성기 : HeaderDoc 대 Doxygen 대 AppleDoc (0) | 2020.10.20 |