You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Swift中WKWebView的goBack()方法无法正常工作问题排查

问题诊断

你的回退功能异常根源在于:拦截了.backForward类型的原生回退导航,并用load(_:)方法重新发起请求。WKWebView的load(_:)会在历史栈顶部新增页面,而非回退到历史栈的上一个页面——原本的回退操作应该移除栈顶页面,但你取消原生回退后,新增了相同URL的页面到栈顶,导致历史栈持续膨胀:

  • 初始栈:[页面A]
  • 加载页面B后:[A, B]
  • 第一次点击返回:拦截回退到A的请求,取消后加载带自定义头的A,栈变为[A, B, A],canGoBack仍为true
  • 第二次点击返回:拦截回退到B的请求,取消后加载带自定义头的B,栈变为[A, B, A, B],canGoBack依旧为true
  • 多次操作后栈被耗尽,canGoBack变为false,才触发关闭逻辑

解决方案

方案一:全局自定义请求头(最简方案)

如果业务场景允许,直接通过WKWebViewConfiguration设置全局附加请求头,所有请求(包括回退导航)会自动携带自定义头,无需拦截导航:

// 初始化WKWebView时配置全局头
let webConfig = WKWebViewConfiguration()
webConfig.additionalHTTPHeaders = [
    "header_key1": "header_value1",
    "header_key2": "header_value2"
]
let webView = WKWebView(frame: view.bounds, configuration: webConfig)

然后删除decidePolicyFor中针对.backForward类型的拦截逻辑,回退方法保留原逻辑即可:

func goBackInWebView(_ webView: WKWebView?) {
    if webView?.canGoBack ?? false {
        webView?.goBack()
        return
    }
    close()
}

注意:该方案适用于多数GET请求场景,若存在POST请求或网页主动修改请求头的情况,需结合其他方式调整。

方案二:手动管理页面层级(兼容复杂场景)

若全局头无法满足需求(如动态修改头、跨域/POST请求),则通过手动维护页面层级替代WKWebView的原生历史栈判断:

步骤1:添加页面层级变量

在WebView控制器中添加变量记录当前页面层级:

private var pageLevel = 1 // 初始页面层级为1

步骤2:修改decidePolicyFor逻辑

只拦截非回退类型的导航,同时更新页面层级:

override func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    self.currentLoadedUrl = navigationAction.request.url
    let requestHeaders = navigationAction.request.allHTTPHeaderFields ?? [:]
    
    // 仅处理非回退类型的导航(点击链接、JS跳转等)
    if navigationAction.navigationType != .backForward,
       requestHeaders["header_key1"] == nil || requestHeaders["header_key2"] == nil,
       let currentUrl = navigationAction.request.url,
       currentUrl != self.getInitialUrl() {
        decisionHandler(.cancel)
        
        var request = URLRequest(url: currentUrl)
        request.setValue("header_value1", forHTTPHeaderField: "header_key1")
        request.setValue("header_value2", forHTTPHeaderField: "header_key2")
        webView.load(request)
        pageLevel += 1 // 加载新页面,层级加1
    } else {
        decisionHandler(.allow)
    }
}

步骤3:修改回退方法逻辑

通过页面层级判断是否回退或关闭控制器:

func goBackInWebView(_ webView: WKWebView?) {
    pageLevel -= 1
    if pageLevel > 0 {
        // 获取历史栈中上一个页面的URL,构造带自定义头的请求加载
        guard let backUrl = webView?.backForwardList.backItem?.url else {
            close()
            return
        }
        var request = URLRequest(url: backUrl)
        request.setValue("header_value1", forHTTPHeaderField: "header_key1")
        request.setValue("header_value2", forHTTPHeaderField: "header_key2")
        webView?.load(request)
    } else {
        close()
    }
}

额外处理:若存在页面刷新(navigationType为.reload)或JS跳转的情况,需根据实际场景调整pageLevel的增减逻辑,避免层级计算错误。


内容的提问来源于stack exchange,提问作者Krima Shah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 10:23:15