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

如何在WKWebView发起原始请求后拦截HTTP/HTTPS调用?

嘿,针对你在iOS WKWebView里拦截所有HTTP/HTTPS请求的需求,结合你用代理服务器转发的场景,我整理了几个实用的方案,应该能帮到你:

方案1:利用WKNavigationDelegate拦截并修改请求

这是最直接的方案,通过WKWebView的导航代理方法,拦截所有即将发起的请求,将其转换为你的代理服务器地址后再重新发起。

核心思路

实现WKNavigationDelegate的webView(_:decidePolicyFor:decisionHandler:)方法,这个方法会在每个请求发起前被调用,你可以在这里检查请求的URL,将原始目标站点的URL替换成你的代理服务器URL,然后取消原始请求,加载新的代理请求。

代码示例

class YourViewController: UIViewController, WKNavigationDelegate {
    private var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let webConfig = WKWebViewConfiguration()
        webView = WKWebView(frame: view.bounds, configuration: webConfig)
        webView.navigationDelegate = self
        view.addSubview(webView)
        
        // 加载初始目标页面,比如Google
        if let targetURL = URL(string: "https://www.google.com") {
            webView.load(URLRequest(url: targetURL))
        }
    }

    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        guard let originalRequestURL = navigationAction.request.url else {
            decisionHandler(.cancel)
            return
        }
        
        // 只拦截HTTP/HTTPS请求,忽略本地资源等其他请求
        guard originalRequestURL.scheme == "http" || originalRequestURL.scheme == "https" else {
            decisionHandler(.allow)
            return
        }
        
        // 将原始URL转换为代理服务器的请求地址
        guard let encodedOriginalURL = originalRequestURL.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
              let proxyURL = URL(string: "https://server.com/\(encodedOriginalURL)") else {
            decisionHandler(.cancel)
            return
        }
        
        // 创建新的代理请求,复制原始请求的头部信息
        var proxyRequest = URLRequest(url: proxyURL)
        proxyRequest.allHTTPHeaderFields = navigationAction.request.allHTTPHeaderFields
        
        // 取消原始请求,加载代理请求
        webView.load(proxyRequest)
        decisionHandler(.cancel)
    }
}

注意事项

  • 一定要及时调用decisionHandler,否则会导致WKWebView卡住;
  • 这个方法会拦截所有类型的HTTP/HTTPS请求,包括主页面加载、图片、脚本、样式等子资源请求,如果你需要区分主框架和子资源,可以通过navigationAction.targetFrame判断;
  • 记得处理URL编码,避免原始URL中的特殊字符导致代理请求地址无效。
方案2:自定义URL Scheme Handler(更灵活的控制)

如果需要更深度地控制请求的整个生命周期(比如自定义请求头、处理响应数据、错误重试等),可以使用WKURLSchemeHandler来注册自定义的URL Scheme,然后拦截该Scheme的请求并转发到代理服务器。

核心思路

  1. 注册一个自定义的URL Scheme(比如myproxy);
  2. 实现WKURLSchemeHandler协议,在该协议方法中处理自定义Scheme的请求,将其转换为代理服务器的HTTPS请求;
  3. 前端页面使用自定义Scheme发起请求,或者在初始加载时就使用该Scheme。

代码示例

自定义Scheme Handler类

class ProxySchemeHandler: NSObject, WKURLSchemeHandler {
    func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
        // 解析自定义Scheme的URL,提取原始目标地址
        guard let originalURLString = urlSchemeTask.request.url?.host?.appending(urlSchemeTask.request.url?.path ?? ""),
              let originalURL = URL(string: originalURLString),
              let encodedOriginalURL = originalURL.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
              let proxyURL = URL(string: "https://server.com/\(encodedOriginalURL)") else {
            let error = NSError(domain: "ProxyError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无效的请求地址"])
            urlSchemeTask.didFailWithError(error)
            return
        }
        
        // 发起代理服务器请求
        let sessionTask = URLSession.shared.dataTask(with: proxyURL) { data, response, error in
            if let error = error {
                urlSchemeTask.didFailWithError(error)
                return
            }
            
            guard let response = response, let data = data else {
                let error = NSError(domain: "ProxyError", code: -2, userInfo: [NSLocalizedDescriptionKey: "无响应数据"])
                urlSchemeTask.didFailWithError(error)
                return
            }
            
            // 将代理服务器的响应返回给WKWebView
            urlSchemeTask.didReceive(response)
            urlSchemeTask.didReceive(data)
            urlSchemeTask.didFinish()
        }
        sessionTask.resume()
    }
    
    func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
        // 这里可以取消正在进行的URLSession任务
        // 如果需要跟踪任务,可以在start方法中保存sessionTask的引用,这里取消
    }
}

初始化WKWebView并注册Scheme

override func viewDidLoad() {
    super.viewDidLoad()
    
    let webConfig = WKWebViewConfiguration()
    // 注册自定义Scheme Handler
    webConfig.setURLSchemeHandler(ProxySchemeHandler(), forURLScheme: "myproxy")
    
    webView = WKWebView(frame: view.bounds, configuration: webConfig)
    view.addSubview(webView)
    
    // 使用自定义Scheme加载目标页面
    if let customURL = URL(string: "myproxy://www.google.com") {
        webView.load(URLRequest(url: customURL))
    }
}

注意事项

  • 自定义Scheme不能是系统已有的(比如http、https、file等);
  • 需要自己处理URLSession的任务管理,比如取消请求、错误处理等;
  • 如果前端页面中有跳转,需要确保跳转的URL也被转换为自定义Scheme,或者在导航代理中再做一次拦截转换。
额外注意点
  • ATS配置:如果你的代理服务器使用自签名HTTPS证书,需要在Info.plist中配置NSAppTransportSecurity的NSAllowsArbitraryLoads(不推荐生产环境),或者添加NSExceptionDomains指定你的代理服务器域名并允许不安全的加载;
  • 跨域问题:确保你的代理服务器正确处理CORS请求头,避免WKWebView中的前端页面出现跨域错误;
  • 缓存策略:如果需要缓存请求结果,可以在拦截时设置合适的缓存策略,或者让代理服务器处理缓存逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 06:54:40