混合應用:從 file 協議到本地 HTTP 伺服器
過去的幾個月裡,我們一直在開發一個混合應用。前端框架使用的是 Angular,但是在某些 Android 機型上執行的時候,報了以下的錯誤:
main.aca1d67….bundle.js:1235 EXCEPTION: Uncaught (in promise): SecurityError: Failed to execute 'replaceState' on 'History': A history state object with URL 'file:///#/' cannot be created in a document with origin 'file://' and URL 'file:///android_asset/www/index.html'.t.handleError @
錯誤的主要原因是:History API 在某些 Chrome 核心的 WebView 上不支援 file:// 協議 。據不完成測試統計,版本在 45~49 之間,都有這個問題。
隨後找到了官方文件中的 issue:ofollow,noindex" target="_blank">Cannot run angular 2+ from file:/// - looks like 'base href="/"' is the issue
官方 issue 中的一個高贊答案,一共兩步,並是不 work。
1.將 Router 配置為 Hash
CommonModule,RouterModule.forRoot(routes,{useHash:true})
2.修改 base href:
<script>document.write('<base href="' + document.location + '" />');</script>
於是乎,這時我們有兩個選擇:
- 重寫 HashLocationStrategy,如下 issue 12341 所說:The router HashLocationStrategy should not use the History API
- 使用 HTTP 伺服器來執行本地的 WebView 資原始檔。
方式一,面對的主要挑戰是,不只 Angular 使用 History API 來處理 hash 路由,其它框架也使用了相似的東西,如 React Router、Vue Router。
方式二,面對的主要問題是,我們需要在 Android 裝置上啟動一個 HTTP 伺服器,並能讓它支援跨域請求和訪問本地檔案。
在這個過程中,想到了 Ionic 框架也是使用 Angular 來編寫的。於是,先運行了個官方的 Hello, world,發現它是執行在http://localhost:8100
上的。
緊接著,複製了官方的 WebView 外掛程式碼:Ionic Web View for Cordova 。隨之,我們就遇到了跨域的問題,原因是這些請求都是通過 WebView 發出去。
而這個問題,又近乎無解,我們無法獲取 WebView post 請求中的引數。於是乎,我們只能通過外掛來向 WebView 提供一個跨域請求的能力:Cordova Advanced HTTP 。