Autodesk Forge API服務的資料中心是基於AWS的海外服務搭建的,因而,由於眾所周知的原因,國內部分地區(依ISP而異)訪問Forge雲埠的速度會受到一定程度的影響。特別是Forge Viewer瀏覽大型模型,以及對反饋時間比較銘感且涉及關鍵業務的工作流等諸多場景,對於服務端的存取效率有者較高要求。所以,如何處理好雲端資料的訪問與協同工作流,包括離線載入、雲端快取等方案的最佳實踐,是大家一直關注的問題。今天,我們就總結一下幾種常見的實現方式,以期實現流程與效能的最佳化。
離線模型載入
往期有這兩篇文章可供參考:離線模型的下載和部署和Viewer模型載入本地離線快取實戰,該文介紹了使用新近瀏覽器原生的Service-Worker和Cache API快取模型的方案。
但是在Viewer模型載入本地離線快取實戰的例項程式碼中,針對Viewer庫和線上模型資源本身的快取是透過靜態路徑實現的:
//https://github.com/petrbroz/forge-disconnected/blob/master/public/service-worker.js
const STATIC_URLS = [
'https://developer.api.autodesk.com/modelderivative/v2/viewers/6.*/style.css',
'https://developer.api.autodesk.com/modelderivative/v2/viewers/6.*/viewer3D.js',
'https://developer.api.autodesk.com/modelderivative/v2/viewers/6.*/lmvworker.js',
'https://developer.api.autodesk.com/modelderivative/v2/viewers/6.*/res/locales/en/allstrings.json',
'https://developer.api.autodesk.com/modelderivative/v2/viewers/6.*/res/environments/SharpHighlights_irr.logluv.dds',
'https://developer.api.autodesk.com/modelderivative/v2/viewers/6.*/res/environments/SharpHighlights_mipdrop.logluv.dds',
...
該實現存在幾點問題:
- 待快取的靜態連結是根據展示用的模型所需配置的,模型更換後靜態連結也需要手動更新
- 一次性快取了所有例項模型所需的資源,超配且不必要,影響載入效能
- Viewer庫版本一旦更新,需手動更新快取的靜態資源連結
因此,在我們後續的實戰Forge Viewer漸進應用一文中,採用先註冊完成快取任務的Service Worker再載入Viewer庫的流程。如此一來,Viewer庫依賴與模型資源的載入請求也會自動得到快取,無需手動干預快取過程,大幅增進程式碼的可維護性:
navigator.serviceWorker.register('/service-worker.js').then((registration) => {
let script = document.createElement('script');
script.onload = function () {
const viewer = new Autodesk.Viewing.Private.GuiViewer3D(myViewerDiv);
Autodesk.Viewing.Initializer(options, () => {
... //按需以線上或離線模式初始化Viewer並載入模型
viewer.addEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT, () => {
const channel = new MessageChannel();
channel.port1.onmessage = (event) => console.log(event);
navigator.serviceWorker.controller.postMessage({ operation: 'EXECUTE_CACHE' }, [channel.port2]); // 模型載入完成,該模型所需資源已作記錄,遂向ServiceWorker傳送訊息,開始快取所需資源
})
});
};
script.src = "https://developer.api.autodesk.com/modelderivative/v2/viewers/6.*/viewer3D.min.js";
document.head.appendChild(script) //待Worker註冊完畢開始作動後再載入Viewer,實現Viewer庫及其依賴的自動快取
})
線上模型載入
- 建議參考下文的資料服務的最佳化,為Viewer的載入提供代理,增進國內訪問的速度。
- 在Viewer上實現代理的方法主要透過
Autodesk.Viewing.endpoint.setEndpointAndApi
來重定向獲取模型資料的URL:
Autodesk.Viewing.Initializer(options, function(){
Autodesk.Viewing.endpoint.setEndpointAndApi('https://yourhostname/your/proxy/service/path')
...
隨後在你的服務端將Viewer發來的請求代理至Forge API雲服務https://developer.api.autodesk.com
即可,注意保留Viewer原生請求的路徑,這裡還可以根據Forge服務上的模型所在的資料中心按需為轉發目的地作進一步設定,詳見:BIM 360 Docs API在操作歐洲資料中心內容的一些調整。
- 亦可設定Viewer傳送的請求頭,以AOP的設計模式實現自己的訪問控制等邏輯:
Autodesk.Viewing.Initializer(options, function(){
Autodesk.Viewing.endpoint.HTTP_REQUEST_HEADERS = {'X-My-Custom-Header':'233', ...}
...
當然,我們還需在自己的服務端設定預檢請求(Pre-flight)的返回中Access-Control-Allow-Headers
的請求頭,允許之前為Viewer設定的請求頭不被瀏覽器的跨域安全機制攔截。
- 當然,大家熟悉的Viewer原生的getAccessToken等都是依舊有效的。
Android
- 如本地的模型,由於Viewer不支援基於
File
協議的模型載入,需要透過重寫WebView並攔截http請求,返回靜態資源。
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("http://my/path/to/svf")) {
// 返回靜態模型資源
return true;
}
}
});
- Viewer載入模型的URL維持http協議即可
iOS
- 同理,iOS的實現思路是:
func webView(_ webView: WKWebView, decidePolicyFor
navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) {
if navigationAction.navigationType == .linkActivated {
if webView.url!.absoluteString == "http://path/to/my/static/svf" {
//返回靜態模型資源
return
}
}
decisionHandler(.allow)
}
- 亦可參考這裡的教程:https://github.com/BKRApps/KR...
跨平臺
針對跨平臺的框架,不建議使用搭設本地靜態伺服器的方式克服Viewer不支援File
協議的問題,因為很多Android ROM處於安全考量已經遮蔽了該特性。
- React Native框架: 推薦使用react-native-webview,再透過
onShouldStartLoadWithRequest
攔截並返回靜態模型:
onShouldStartLoadWithRequest = (event) => {
var url = event.url;
if (url && url.length) {
if (url.indexOf('http://my/path/to/svf') == 0) {
//返回靜態模型資源
}
}
return true;
};
-
Ionic框架
- 推薦使用cordova-plugin-ionic-webview,再透過
onShouldStartLoadWithRequest
攔截並返回靜態模型 - 再結合Cordova File Plugin訪問靜態資源
cdvfile://path/to/svf
- 推薦使用cordova-plugin-ionic-webview,再透過
資料服務的最佳化
- 建議自建雲服務訪問Forge API或部署代理,以便實現諸多最佳化事項,如快取(可以使用http-cache等庫),如集中統籌Access Token,避免為每個客戶端服務請求逐一作Forge認證,提升效率的同時增強Forge App金鑰和Token的安全性,亦便於實現高度自定的工作流。
- 建議搭建位於海外機房的節點作代理,地理位置推薦香港或接入電信CN2線路的北美機房,訪問速度會有不小提升,詳情可以自行搜尋瞭解。
- 亦可搭建自己的雲端儲存,便於實現高度自定義的工作流與高規格的安全機制,可以透過等Ceph和minio等技術實現。
- 活用Forge Webhook API,實現基於事件回撥的非同步工作流,節省資源的同時提高可靠性,詳情可以參考這些樣例。
Q&A
Q:能否避免將模型上傳到Forge資料平臺,直接進行轉換?
- A:Forge服務只能轉換儲存在Forge資料平臺的模型,轉換功能無法作本地部署,如模型涉密,可以再轉換完成後立即從Forge資料平臺刪除,Forge對使用者資料不作任何備案。
Q:可否實現Viewer的完全本地化?即將Viewer庫和模型渲染資源下載到本地?
- A:Forge Viewer使用許可禁止將Viewer庫下載至本地載入,亦禁止對程式碼進行修改
Q: 那如何修改Viewer原始碼?我有擴充套件原生邏輯的需求。
- A: 可以使用
Piggyback
的方式,即在自己的邏輯中動態的替換、擴充套件Viewer自身的函式
Q: 針對離線載入模型的場景,如何有效的提取Viewer可讀的模型檔案(SVF)到本地?
- A: 可以透過我們搭建的Extractor應用提取:https://extract.autodesk.io/,亦可自行部署該應用:https://github.com/cyrillef/e...