Using TransferState API in an Angular v5 Universal App
讓我們用一個具體的例子來說明這篇文章。 我們有一個天氣應用程式,在其側邊欄中顯示城市清單。 當您單擊城市名稱時,該應用程式會顯示該城市的目前天氣。
因為我們希望我們的應用程式是可抓取和可索引的,是以我們使它通用:城市頁面在伺服器上呈現,存儲為 HTML 檔案并由 HTTP 伺服器提供服務。 這些頁面将包含浏覽器應用程式,是以使用者可以在加載第一頁後使用 Angular 的強大功能繼續在應用程式中導航。
您可以按照以下步驟嘗試這個簡單的示例。
使用下列指令将這個例子 clone 到本地:
您現在可以使用首選的 HTTP 伺服器為 dist 目錄提供服務。
現在,如果您直接通路頁面 http://your-domain/Paris(這是通路者來自搜尋引擎的典型情況),您可以觀察到頁面閃爍 - 這是因為内容已經存在并且已經下載下傳到本地了,然後浏覽器應用程式會重新加載并再次顯示。
TransferState to the rescue
Angular v5 中引入的 TransferState API 可以幫助解決這種情況。 它可以将資料從應用程式的伺服器端傳輸到浏覽器應用程式。
為此,伺服器應用程式将在它生成的 HTML 頁面中添加我們要傳輸的資料。
包含在此生成的 HTML 頁面中的浏覽器應用程式将能夠讀取此資料。
在這個分支檢視解決方案。
現在,在為元件提供資料的解析器中,我們可以使用 TransferState API:
在伺服器上,我們首先注冊 onSerialize 以提供我們将下載下傳的資料,然後我們從我們的資料提供者那裡擷取資料,這裡是一個 HTTP GET 請求。
在浏覽器上,我們使用get方法來擷取server提供的資料,我們直接提供這些資料。 我們還從傳輸狀态中删除了提供的資料,是以頁面的重新加載将不再使用提供的資料。
我們可以通過調用 hasKey 方法來檢測我們是在伺服器上還是在浏覽器應用程式上。 此方法僅在浏覽器中傳回 true。
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<CityWeather> {
const found = this.transferState.hasKey(RESULT_KEY);
if (found) {
const res = Observable.of(this.transferState.get<CityWeather>(RESULT_KEY, null));
this.transferState.remove(RESULT_KEY);
return res;
} else {
this.transferState.onSerialize(RESULT_KEY, () => this.result);
const name = route.params['city'];
return this.http.get<CityWeather>('https://api.openweathermap.org/data/2.5/weather?q=' + name + '&units=metric&APPID=' + this.key)
.do(result => this.result = result);
}
}
因為我們是調用remove方法移除提供的資料,是以浏覽器顯示的以下頁面會調用onSerialize方法,但是這個方法沒有效果,因為toJson隻在服務端調用。
一個更清晰的解決方案是使用 isPlatformServer 和 isPlatformBrowser 方法來檢測平台并采取相應的行動。