项目调用苹果私有API,为了拦截 WKWebView 发出的网络请求,但是方法名已经使用 Base64 进行了编码,为了防止苹果静态扫描和检查,因此存在一定风险,请大家合理利用,最安全还是在 Debug 下,开发中使用。
该项目调用苹果私有API,为了拦截 WKWebView 发出的网络请求,但是API签名已使用Base64进行编码,为了防止苹果静态扫描和检查,所以存在一定风险,请合理利用,最安全还是在 Debug 下,开发中使用。
如果 HTTPInterceptor 对您有帮助,给博主一个小星星
如有疑问,欢迎来提 issue,你们的提问是对楼主最好的反馈。
如果 HTTPInterceptor 对您有帮助,请为项目点个赞
关于 HTTPInterceptor
新功能:我为 HTTPInterceptor 新增了 Mock Data 的功能,API 非常简单清晰,使用非常方便。我已经为 HTTPInterceptor 添加了 Mock Data 功能,API 简单明了,使用非常方便。
HTTPInterceptor 是一个 iOS 网络请求拦截器,它可以拦截基于 URLSession 和 NSURLConnection 发出的 HTTP(s) 请求。对于已经使用过 URLProtocol 的项目来说,如果 HTTPInterceptor 和其他 URLProtocol Handle 的 URL 一样,就要看注入的先后顺序。
- 您可以使用它来拦截一个特定的请求,然后返回一个新的请求,这意味着您可以改变它访问的目标地址和参数等。
- 您可以使用它来拦截一个特定的请求,然后返回一个新的 URLResponse 和 Data,这意味着您可以返回一个自定义的 Response,例如 Mock 数据等操作。
- 您可以使用它来拦截一个特定的请求,然后返回一个 URLSessionTaskMetrics,这意味着您可以得到这个 Request 创建的请求 Task 的性能指标,例如创建 Task,DNS Lookup,Establish 连接等,用于数据上报等。
HTTPInterceptor 是一个 iOS 网络请求拦截器,它可以拦截由 URLSession 和 NSURLConnection 发出的 HTTP(s) 请求。
- 您可以拦截一个特定的请求并返回一个新请求。
- 它可以拦截一个特定的请求并返回一个特定的响应和数据。
- 它还可以拦截一个特定的请求并回调 URLSessionTaskMetrics 对象。
关于 WKWebView
HTTPInterceptor 虽然可以拦截 WKWebView 中的网络请求,但是都无法得到 POST 请求的 HTTPBody。因为拦截 WKWebView 的网络请求,HTTPInterceptor 使用了苹果的私有API,这是不安全的,也是不应该的,但是如果您是在 Debug 下使用它,这就另当别论了。
关于如何获取 WKWebView 中 POST 请求的 HTTPBody,我查阅了一些文章。例如:WKWebView 注入 JS 脚本,JS 脚本 Hook 所有的 XHR 和 Fetch 网络请求,然后再通过 Native 和 Web 通信通道,等等。
可以看到,这样的逻辑确实有点麻烦,而且需要考虑的东西非常多,因为您是 Hook 了 JS 的请求入口,这是一个 block 操作,稍有不慎就会给 H5 带来线上灾难,而且全部都是为了拿一个 HTTPBody,因此我认为这是非常不值得的,为了程序的鲁棒性,也不应该使用这样的实现。
使用 HTTPInterceptor 获取 HTTPBody 不受支持。
关于名称
由于 HttpInterceptor
名称已被他人占用,因此请使用 BestHttpInterceptor
。
示例
要运行示例项目,请克隆仓库,然后首先从示例目录运行 pod install
。
一,Mock数据(Mock数据)
1. 注册拦截条件
import BestHttpInterceptor
// Mock URL
let jsonURL: URL = URL(string: "https://mocker.example.com/json?arg1=1234567890")!
let pngURL: URL = URL(string: "https://mocker.example.com/png?arg1=1234567890")!
let jpgURL: URL = URL(string: "https://mocker.example.com/jpg?arg1=1234567890")!
let gifURL: URL = URL(string: "https://mocker.example.com/gif?arg1=1234567890")!
let htmlURL: URL = URL(string: "https://mocker.example.com/html?arg1=1234567890")!
let pdfURL: URL = URL(string: "https://mocker.example.com/pdf?arg1=1234567890")!
let URLS: [URL] = [jsonURL,pngURL,jpgURL,gifURL,htmlURL,pdfURL]
class MockerTemplateViewController: UIViewController {
var interceptor: HttpInterceptor!
override func viewDidLoad() {
super.viewDidLoad()
registerInterceptor()
doTask()
}
deinit {
// 不再使用的时候,记得注销interceptor
print("MockerTemplateViewController deinit")
interceptor.unregister()
}
func registerInterceptor() {
// 拦截你想要的URL,根据URLRequest参数,给这个回调返回一个Bool值。
let condition = HttpIntercepCondition.init(schemeType: .all) { (request) -> Bool in
if let url = request.url, URLS.contains(url) {
return true
}
return false
}
interceptor = HttpInterceptor(condition: condition, mockerDelegate: self)
interceptor.register()
}
func doTask() {
// 开始一个普通的网络请求,它的返回值,应该是你在Mocker代理里面返回的值。
URLSession.shared.dataTask(with: jsonURL) { (data, response, error) in
if let e = error {
print("e:\(e)")
} else {
let jsonStr = String(data: data!, encoding: .utf8)
DispatchQueue.main.async {
self.contentLabel.text = jsonStr
}
}
}.resume()
}
}
2. 实现 HttpMockerDelegate 代理
extension MockerTemplateViewController: HttpMockerDelegate {
// 根据拦截到的URLRequest,返回本地假数据。
func httpMocker(request: URLRequest) -> HttpMocker {
guard let url = request.url else { fatalError() }
switch url {
case jsonURL:
let jsonUrl = Bundle(for: MockerTemplateViewController.self).url(forResource: "mock_json", withExtension: "json")!
let mocker = HttpMocker(dataType: .json, mockData: jsonUrl.data, statusCode: 200, httpVer: .http1_1)
return mocker
default:
fatalError()
}
}
}
二,拦截请求(拦截请求)
1. 注册拦截条件
import UIKit
import WebKit
import BestHttpInterceptor
class WKViewController: UIViewController {
@IBOutlet weak var webview: WKWebView!
var interceptor: HttpInterceptor? = nil
enum PathExtension: String {
case gif = "gif"
case png = "png"
case jpeg = "jpeg"
case svg = "svg"
case jpg = "jpg"
}
override func viewDidLoad() {
super.viewDidLoad()
title = "WKWebViewController"
registerInterceptor()
let url = URL(string: "https://www.baidu.com/")
webview.load(URLRequest(url: url!))
}
func registerInterceptor() {
// 定义拦截条件,根据URLRequest参数来进行判断,是否需要拦截此Request,返回Bool告诉HTTPInterceptor。
let condition = HttpIntercepCondition(schemeType: .all) { (request) -> Bool in
// 拦截逻辑,这里是要拦截host带有ss和timgmb和结尾是 gif,jpeg,png,svg,jpg的Request。
// 大家可以根据自己的需求来定义这个条件。
guard let pathExtensionStr = request.url?.pathExtension,
let host = request.url?.host else {
return false
}
if host.contains("ss") || host.contains("timgmb") {
return true
}
let pathExtension = WKViewController.PathExtension(rawValue: pathExtensionStr)
switch pathExtension {
case .gif,.jpeg,.png,.svg,.jpg:
return true
case .none:
return false
}
}
interceptor = HttpInterceptor(condition: condition, interceptorDelegate: self)
// 开始注册
interceptor?.register()
}
deinit {
print("WKViewController deinit")
// 取消注册
interceptor?.unregister()
}
}
2. 实现 HttpInterceptDelegate 代理
extension WKViewController: HttpInterceptDelegate {
// Replace Request URL
func httpRequest(request: URLRequest) -> URLRequest {
// 将拦截到的Request,换成我们新的Request。
var newRequest = request
newRequest.url = URL(string: "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1577182928067&di=4a039119f074e775880d33ee7589e556&imgtype=0&src=http%3A%2F%2Fimg.mp.itc.cn%2Fupload%2F20170307%2Fc1529f8154f949ef83abee83f6d5ece7.jpg")!
return newRequest
}
}
特点
- 根据URL创建模拟数据请求
- 支持Alamofire等流行框架
- WKWebView、UIWebView、URLSession、URLConnection,所有网络HTTP(s)请求均可被拦截。
- 无法拦截WKWebView POST请求的HTTPBody。
- 自定义过滤URLRequest。
- 可拦截并替换URLRequest、URLResponse、Data。
用法
一,Mock 数据 (Mock数据)
1.定义拦截条件
let condition = HttpIntercepCondition(schemeType: .all) { (request) -> Bool in
return true
}
2.创建拦截器实例
let interceptor = HttpInterceptor(condition: condition, mockerDelegate: self)
3.开始注册
interceptor.register()
4.取消注册
interceptor.unregister()
5.实现HttpMockerDelegate
委托,返回到您那里
extension MockerTemplateViewController: HttpMockerDelegate {
// 例子
// Example
func httpMocker(request: URLRequest) -> HttpMocker {
let jsonUrl = Bundle(for: MockerTemplateViewController.self).url(forResource: "mock_json", withExtension: "json")!
let mocker = HttpMocker(dataType: .json, mockData: jsonUrl.data, statusCode: 200, httpVer: .http1_1)
return mocker
}
}
二,拦截请求 (拦截请求)
1.定义拦截条件
let condition = HttpIntercepCondition(schemeType: .all) { (request) -> Bool in
return true
}
2.创建拦截器实例
let interceptor = HttpInterceptor(condition: condition, interceptorDelegate: self)
3.开始注册
interceptor.register()
4.取消注册
interceptor.unregister()
5.实现HttpInterceptorDelegate
委托,返回到您那里
extension SomeClass: HttpInterceptDelegate {
// Intercept http request then return a new request
func httpRequest(request: URLRequest) -> URLRequest {
return request
}
// Intercept http response then return a new response
func httpRequest(response: URLResponse) -> URLResponse {
return response
}
// Intercept http response data then return a new response data
func httpRequest(request: URLRequest, data: Data) -> Data {
return data
}
// When the request is complete call this api
func httpRequest(request: URLRequest, didCompleteWithError error: Error?) {
}
func httpRequest(request: URLRequest, didFinishCollecting metrics: URLSessionTaskMetrics) {
}
}
要求
iOS 10+
安装
HttpInterceptor可通过CocoaPods使用。要安装它,只需将以下行添加到Podfile中
pod 'BestHttpInterceptor'
如果您希望使用调试模式
pod 'BestHttpInterceptor',:configurations => ['Debug']
作者
zColdWater
许可证
HttpInterceptor可在MIT许可证下使用。有关更多信息,请参阅LICENSE文件。