Forge云服务的本地化经验总结与优化实战
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对用户数据不作任何备案。
- A:Forge Viewer使用许可禁止将Viewer库下载至本地加载,亦禁止对代码进行修改
- A: 可以使用
Piggyback
的方式,即在自己的逻辑中动态的替换、扩展Viewer自身的函数
- A: 可以通过我们搭建的Extractor应用提取:https://extract.autodesk.io/,亦可自行部署该应用:https://github.com/cyrillef/e...