HarmonyOS鸿蒙Next中使用webview加载网页跨域问题
HarmonyOS鸿蒙Next中使用webview加载网页跨域问题 使用uniapp开发鸿蒙应用,web组件加载网页时报跨域问题
可参考demo:
import harmonyWebView from '@ohos.web.webview'
import picker from '@ohos.file.picker';
import { BusinessError } from '@ohos.base';
import { abilityAccessCtrl, common } from '@kit.AbilityKit';
import { util } from '@kit.ArkTS';
interface Detail {}
interface Event {
detail: Detail
}
interface TitleUpdateEventDetail {
title?: string
}
interface TitleUpdateEvent extends Event {
detail: TitleUpdateEventDetail
}
@Component
export struct WebView {
@Prop @Watch('loadSrc') src: string
onMessage?: (event: Event) => void = undefined
onTitleUpdate?: (event: TitleUpdateEvent) => void = undefined
onPostMessageToService?: (event: Event) => void = undefined
exposeWebViewController?: (controller: harmonyWebView.WebviewController) => void = undefined
controller = new harmonyWebView.WebviewController()
url: string = ''
aboutToAppear(): void {
this.exposeWebViewController?.(this.controller)
}
build() {
Web({
src: '',
controller: this.controller
})
.overScrollMode(OverScrollMode.NEVER)
.keyboardAvoidMode(WebKeyboardAvoidMode.RESIZE_VISUAL)
.geolocationAccess(true)
.domStorageAccess(true)
.imageAccess(true)
.fileAccess(true)
.onTitleReceive(event => {
this.onTitleUpdate?.({
detail: {
title: event?.title
}
})
})
.onConsole(event => {
if (event) {
console.log('getMessage: ' + JSON.stringify(event.message.getMessage()))
}
return false
})
.onErrorReceive(event => {
if (event) {
console.error(event.error.getErrorInfo())
}
})
.javaScriptProxy({
object: {
postMessage: (data: string) => {
if (this.onMessage) {
this.onMessage({ detail: JSON.parse(data) })
}
},
postMessageToService: (data: string) => {
if (this.onPostMessageToService) {
this.onPostMessageToService({ detail: JSON.parse(data) })
}
}
},
name: '__uniapp_x_',
methodList: ['postMessage', 'postMessageToService'],
controller: this.controller
})
.onGeolocationShow(event => {
let context = getContext(this) as common.UIAbilityContext;
let atManager = abilityAccessCtrl.createAtManager();
atManager.requestPermissionsFromUser(context, ["ohos.permission.APPROXIMATELY_LOCATION"]).then(data => {
console.info('data authResults:' + data.authResults);
}).catch(error: BusinessError => {
console.error(`Failed to request permissions from user. Code is ${error.code}, message is ${error.message}`);
})
AlertDialog.show({
title: '位置权限请求',
message: '是否允许获取位置信息',
primaryButton: {
value: 'cancel',
action: () => {
if (event) {
event.geolocation.invoke(event.origin, false, false);
}
}
},
secondaryButton: {
value: 'ok',
action: () => {
if (event) {
event.geolocation.invoke(event.origin, true, true);
}
}
},
cancel: () => {
if (event) {
event.geolocation.invoke(event.origin, false, false);
}
}
})
})
.onShowFileSelector(event => {
const selectOptions = new picker.PhotoSelectOptions();
const mode = event?.fileSelector.getMode();
const acceptType = event?.fileSelector.getAcceptType();
if (mode === 0) {
selectOptions.maxSelectNumber = 1;
}
if (acceptType) {
let type = "";
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.svg', '.webp'];
const containsImage = imageExtensions.some((ext: string): boolean => acceptType.includes(ext));
const videoExtensions =
['.mp4', '.mov', '.avi', '.mkv', '.flv', '.wmv', '.ogg', '.webm', 'mpg', 'mpeg', '.3gp', 'rm', 'rmvb',
'm4v', 'wma', 'mts'];
const containsVideo = videoExtensions.some((ext: string): boolean => acceptType.includes(ext));
if (containsImage && containsVideo) {
type = "IMAGE_VIDEO_TYPE";
} else if (containsImage) {
type = "IMAGE_TYPE";
} else if (containsVideo) {
type = "VIDEO_TYPE";
}
if (type) {
selectOptions.MIMEType = picker.PhotoViewMIMETypes[type]
}
}
let filePaths: Array<string> | null = null;
const viewPicker = new picker.PhotoViewPicker();
viewPicker.select(selectOptions).then(selectResult => {
filePaths = selectResult.photoUris;
if (event) {
event.result.handleFileList(filePaths);
}
}).catch(err: BusinessError => {
console.error(`Invoke viewPicker.select failed, code is ${err.code}, message is ${err.message}`);
})
return true
})
.onHttpErrorReceive(event=>{
console.info('dddddd', JSON.stringify(event.response.getResponseData()), JSON.stringify(event.response.getResponseHeader()), event.request.getRequestUrl())
})
.onControllerAttached(()=>{
// controller和web建联
this.loadSrc()
})
}
// 加载页面
loadSrc() {
if(!this.src) {
return
}
if(this.src.indexOf('resource://rawfile/') > -1){
// rawfile中的资源
let rawfilePath = this.src.split('resource://rawfile/')[1]
console.info('test')
// script解析有问题,
// this.controller.loadUrl(this.src)
getContext(this).resourceManager.getRawFileContent(rawfilePath, (_err, value) => {
let decoder = util.TextDecoder.create('utf-8');
// buffer转化为str
let str = decoder.decodeWithStream(value);
this.controller.loadData(str,"text/html", "UTF-8", 'https://*.com')
});
}else{
this.controller.loadUrl(this.src)
}
}
}
更多关于HarmonyOS鸿蒙Next中使用webview加载网页跨域问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next中,WebView组件加载网页时,跨域问题主要是由于浏览器的同源策略限制导致的。同源策略要求网页只能访问与其源(协议、域名、端口)相同的资源,否则会触发跨域限制。
鸿蒙Next中的WebView默认遵循同源策略,因此在加载跨域资源时可能会遇到限制。为解决跨域问题,可以通过以下方式处理:
-
CORS(跨域资源共享):服务器端可以通过设置HTTP响应头(如
Access-Control-Allow-Origin
)来允许特定域或所有域访问资源。鸿蒙Next的WebView会遵循这些响应头。 -
代理服务器:在鸿蒙应用中设置代理服务器,将跨域请求转发到同源地址,从而绕过浏览器同源策略。
-
iframe跨域通信:使用
postMessage
API实现跨域iframe之间的安全通信。鸿蒙Next的WebView支持该API。 -
WebView设置:鸿蒙Next的WebView提供了相关设置接口,允许开发者自定义跨域行为。例如,可以通过
WebSettings
类配置是否允许跨域访问。
需要注意的是,跨域问题的处理应遵循安全性原则,避免引入安全漏洞。
在HarmonyOS鸿蒙Next中使用WebView加载网页时,若遇到跨域问题,可以通过以下方式解决:
-
配置CORS:确保服务器端正确配置了
Access-Control-Allow-Origin
头,允许WebView所在的域访问资源。 -
使用代理服务器:通过代理服务器转发请求,避免直接跨域访问。
-
本地资源加载:将网页资源(如HTML、CSS、JS)打包到应用中,通过
file://
协议加载,避免跨域限制。 -
WebView设置:在WebView中启用JavaScript和允许跨域请求:
WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setAllowUniversalAccessFromFileURLs(true);
-
安全策略:确保跨域请求符合应用的安全策略,避免引入安全风险。
通过以上方法,可以有效解决HarmonyOS鸿蒙Next中WebView加载网页的跨域问题。