如何在WKWebView发起原始请求后拦截HTTP/HTTPS调用?
嘿,针对你在iOS WKWebView里拦截所有HTTP/HTTPS请求的需求,结合你用代理服务器转发的场景,我整理了几个实用的方案,应该能帮到你:
这是最直接的方案,通过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的请求并转发到代理服务器。
核心思路
- 注册一个自定义的URL Scheme(比如
myproxy); - 实现
WKURLSchemeHandler协议,在该协议方法中处理自定义Scheme的请求,将其转换为代理服务器的HTTPS请求; - 前端页面使用自定义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
相关产品推荐
相关产品推荐

