场景描述
在应用开发时会碰到页面自动跳转的重定向现象,根据业务需求,需要对重定向进行一些判断和处理。
方案描述
重定向是指当用户访问一个网页时,服务器将用户的请求指向另一个页面的过程。通常,服务器会返回一个特定的状态码来告诉浏览器该进行重定向操作。
- 永久重定向:使用状态码 301 (Moved Permanently) 或 308 (Permanent Redirect) 表示,用于更改站点的 URL 并保留现有链接。
- 临时重定向:使用状态码 302 (Found)、303 (See Other) 或 307 (Temporary Redirect) 表示,用于暂时性的资源访问或显示进度页面。
- 特殊重定向:例如状态码 304 (Not Modified) 和 300 (Multiple Choice),用于不同的场景,如缓存验证。
Webview中重定向的触发方式以及判断:
目前在Webview中,网址发生重定向和和页面跳转的样式类似,都是更改了url来加载出不同的内容,JavaScript可以通过window.location.replace("url")和window.location.href="url"两种方式实现页面跳转,将<meta\>标签中的http-equiv属性的值设置为refresh也可以实现页面跳转。
在Webview中可以使用以下方法将直接跳转和系统重定向区分开来:
web有拦截url的回调onLoadIntercept,该回调中的event.data.isRedirect()方法可以实现判断以上几种类型跳转的方式。
场景一:通过回调判断重定向的触发方式
方案
使用web回调onLoadIntercept,该回调中的event.data.isRedirect()方法可以判断是直接跳转还是系统重定向跳转。
核心代码
示例一:通过window.location.href="url"方式进行跳转。
<!-- jump.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>跳转示例</title>
<script>
// 在页面加载完成后立即跳转
window.location.href = "https://developer.huawei.com/consumer/cn/?ha_linker=eyJ0cyI6MTcwODEyOTY4MDk5MywiaWQiOiI5NGE4Y2U3YzZkNWFjMzI1M2VlOWRkNjBhMWNhYjMwZCJ9";
</script>
</head>
<body>
跳转示例
</body>
</html>
示例二:通过<meta\>标签的http-equiv属性进行页面跳转。
<!-- metaJump.html -->
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=gb2312" />
<meta
http-equiv="Refresh"
content="3;url=https://developer.huawei.com/consumer/cn/?ha_linker=eyJ0cyI6MTcwODEyOTY4MDk5MywiaWQiOiI5NGE4Y2U3YzZkNWFjMzI1M2VlOWRkNjBhMWNhYjMwZCJ9"
/>
</head>
<body>
<p>
您将被自动跳转到<a
href="https://developer.huawei.com/consumer/cn/?ha_linker=eyJ0cyI6MTcwODEyOTY4MDk5MywiaWQiOiI5NGE4Y2U3YzZkNWFjMzI1M2VlOWRkNjBhMWNhYjMwZCJ9"
>https://developer.huawei.com/consumer/cn</a
>
</p>
<p>3秒后页面将跳转。</p>
<p>如果页面未跳转,请点击上面的链接。</p>
</body>
</html>
在web组件的拦截url方法onLoadIntercept中将返回值设置为false,即可正常加载页面,不进行拦截。加载完成这个本地H5后可以发现isRedirect返回值为false,没有进入到系统重定向判断中,当点击按钮使用web的loadUrl方法加载一个可以发生系统重定向的链接后,isRedirect为true判定到了系统重定向。
import webview from '@ohos.web.webview';
@Entry
@Component
struct Index {
controller: WebviewController = new webview.WebviewController();
redirectUrl: string = 'https://test url';
@State redirectRes: string = '';
build() {
Column() {
Button(`Load Server Redirect Url`).onClick((event: ClickEvent) => {
this.controller.loadUrl(this.redirectUrl);
})
Web({
src: $rawfile('jump.html'),
controller: this.controller
})
.domStorageAccess(true)
.onLoadIntercept((event) => {
if (event) {
if (event.data.isRedirect()) {
console.log('发生3xx系统重定向')
console.log('系统重定向后url为: ' + event.data.getRequestUrl())
} else {
console.log('普通页面跳转')
console.log('跳转后url为:' + event.data.getRequestUrl())
}
}
return false;
})
}
}
}
日志信息:
场景二:url重定向后通过历史栈回退到上一页面后再次自动跳转到重定向后的页面
当使用web组件加载一个链接进行系统重定向后,该链接存在了历史栈中,当根据历史栈返回到这个发生重定向之前的链接后,又会发生重定向,这样就出现了一直返回一直没有退出的现象。
方案
在监听左滑返回的生命周期onBackPress中先判断accessBackward的值,即当前页面是否有返回历史记录。当accessBackward的返回值为true时,再判断一下是否发生了系统重定向,如果发生了,则根据重定向的次数,使用web的按照历史栈前进或者后退指定步长页面的方法backOrForward设置值为负数,即可根据页面历史栈回退相应的步数
核心代码
设置一个布尔变量和number变量,将是否发生重定向赋值给布尔变量,然后在web的拦截回调onLoadIntercept中判断是否发生重定向,如果isRedirect的值为true,则会将number变量的值减一,发生几次重定向就会相应的减去几次1,这样即可根据重定向的次数来回退不同的步数。在发生系统重定向后又进行普通页面跳转时,在onLoadIntercept回调里将普通跳转的情况给布尔变量isRedirect设置为false,这样在onBackPress生命周期中,就会进入到回退一步的判断里,从而实现正常的跳转后页面回退一步。
import web_webview from '@ohos.web.webview'
@Entry
@Component
struct WebComponent {
controller: web_webview.WebviewController = new web_webview.WebviewController()
@State isRedirect: boolean = false
@State num: number = 1
onBackPress(): boolean | void {
if (this.controller.accessBackward()) {
if (this.isRedirect) {
this.controller.backOrForward(this.num - 2)
} else {
this.controller.backOrForward(-1)
}
return true;
}
return false;
}
build() {
Column() {
Web({ src: $rawfile('jump.html'), controller: this.controller })
.domStorageAccess(true)
.javaScriptAccess(true)
.onLoadIntercept((event) => {
if (event.data.isRedirect()) {
this.isRedirect = true
this.num--
} else {
this.isRedirect = false
}
return false
})
}
}
}
场景三:通过rcp获取到系统重定向后的响应头
当一个链接发生重定向后,想要知道链接重定向后的状态码和重定向后的网址。
方案
可以使用rcp模块的session.get方法获取响应头,从而拿到需要的信息。
核心代码
import { BusinessError } from '@kit.BasicServicesKit';
import { rcp } from '@kit.RemoteCommunicationKit';
@Entry
@Component
struct PageChongDinxiang3 {
build() {
RelativeContainer() {
Button('获取响应头').onClick(() => {
const session = rcp.createSession();
session.get("https://test url").then((response) => {
console.info(`${JSON.stringify(response.headers)}`);
}).catch((err: BusinessError) => {
console.error(`err: err code is ${err.code}, err message is ${err.message}`);
});
})
}
.height('100%')
.width('100%')
}
}
拿到的信息如下,rms3-status字段是http状态码,location是重定向后的链接。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。