鸿蒙开发文档中有一节 加载本地页面 提到了可以通过 $rawfile
方法加载本地 HTML 网页:
Index.ets 1 Web ({ src : $rawfile("local.html" ), controller : this .webviewController })
但是如果在 local.html 中需要引用一些静态资源,例如图片、JS、CSS 等,静态资源放在 local.html 同级目录下,会出现跨域的错误:
Console 1 Access to ... at 'resource://...' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, arkweb, data, chrome-extension, chrome, https, chrome-untrusted.
这是因为本地资源的 URL 是以 resource://
开头的,Web 组件没有这种类型 URL 的跨域处理策略。
怎样解决跨域问题?我想到了一种通过 onInterceptRequest
拦截请求解决跨域的方法,在此分享,该方法 不一定是最佳实践 ,但确实能够解决跨域。
解决加载本地资源的跨域问题 Index.ets 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 import url from '@ohos.url' ;import web_webview from '@ohos.web.webview' ;@Entry @Component struct Index { webviewController : web_webview.WebviewController = new web_webview.WebviewController (); responseResource : WebResourceResponse = new WebResourceResponse (); localMockUrl : string = 'http://myapp.local' ; aboutToAppear ( ) { web_webview.WebviewController .setWebDebuggingAccess (true ); } build ( ) { Column () { Web ({ src : `${this .localMockUrl} /local.html` , controller : this .webviewController }) .onInterceptRequest ((event ) => { if (event) { const requestUrl = event.request .getRequestUrl () if (requestUrl.startsWith (this .localMockUrl )) { const relativePath = url.URL .parseURL (requestUrl).pathname .replace (/^\// , '' ); const resource = $rawfile(relativePath); this .responseResource .setResponseData (resource); this .responseResource .setResponseEncoding ('utf-8' ); let mimeType = "text/plain" ; if (relativePath.endsWith (".html" )) { mimeType = "text/html" ; } else if (relativePath.endsWith (".css" )) { mimeType = "text/css" ; } else if (relativePath.endsWith (".js" )) { mimeType = "text/javascript" ; } else if (relativePath.endsWith (".png" )) { mimeType = "image/png" ; } else if (relativePath.endsWith (".gif" )) { mimeType = "image/gif" ; } else if (relativePath.endsWith (".svg" )) { mimeType = "image/svg+xml" ; } else if (relativePath.endsWith (".pdf" )) { mimeType = "application/pdf" ; } else { } this .responseResource .setResponseMimeType (mimeType); this .responseResource .setResponseCode (200 ); this .responseResource .setReasonMessage ('OK' ); return this .responseResource ; } } return null ; }) } } }
解决加载网络资源的跨域问题 如果跨域是因为 H5 需要向服务器请求获取数据,不是加载本地资源文件导致的,可以把上面代码中的 localMockUrl
改成和服务器相同的 origin(例如 http://api.xxx.com
,结尾不要带 /
),实现本地资源和服务器资源同域,并在 onInterceptRequest
中补充下面的判断:
1 2 3 4 5 if (relativePath.startsWith ("api/" )) { return null ; }
效果:
还不明白的可以拉这个仓库自己试验: https://gitee.com/imaegoo/hm-cors-demo
代码在 entry/src/main/ets/pages/Index.ets
和 entry/src/main/resources/rawfile/local.html
里