BestHttpInterceptor 1.1.0

BestHttpInterceptor 1.1.0

Yongpeng.Zhu 维护。



HTTPInterceptor: intercepting http/https request

CI Status Version Language Version License Platform

项目调用苹果私有API,为了拦截 WKWebView 发出的网络请求,但是方法名已经使用 Base64 进行了编码,为了防止苹果静态扫描和检查,因此存在一定风险,请大家合理利用,最安全还是在 Debug 下,开发中使用。

该项目调用苹果私有API,为了拦截 WKWebView 发出的网络请求,但是API签名已使用Base64进行编码,为了防止苹果静态扫描和检查,所以存在一定风险,请合理利用,最安全还是在 Debug 下,开发中使用。🙏🙏

如果 HTTPInterceptor 对您有帮助,给博主一个小星星这是对博主最好的支持和动力。
如有疑问,欢迎来提 issue,你们的提问是对楼主最好的反馈。

如果 HTTPInterceptor 对您有帮助,请为项目点个赞这是对我最好的支持。如果您有任何问题,请提交 issue 给我。您的 issue 是对我最好的反馈。

关于 HTTPInterceptor

新功能:我为 HTTPInterceptor 新增了 Mock Data 的功能,API 非常简单清晰,使用非常方便。我已经为 HTTPInterceptor 添加了 Mock Data 功能,API 简单明了,使用非常方便。

HTTPInterceptor 是一个 iOS 网络请求拦截器,它可以拦截基于 URLSession 和 NSURLConnection 发出的 HTTP(s) 请求。对于已经使用过 URLProtocol 的项目来说,如果 HTTPInterceptor 和其他 URLProtocol Handle 的 URL 一样,就要看注入的先后顺序。

  1. 您可以使用它来拦截一个特定的请求,然后返回一个新的请求,这意味着您可以改变它访问的目标地址和参数等。
  2. 您可以使用它来拦截一个特定的请求,然后返回一个新的 URLResponse 和 Data,这意味着您可以返回一个自定义的 Response,例如 Mock 数据等操作。
  3. 您可以使用它来拦截一个特定的请求,然后返回一个 URLSessionTaskMetrics,这意味着您可以得到这个 Request 创建的请求 Task 的性能指标,例如创建 Task,DNS Lookup,Establish 连接等,用于数据上报等。

HTTPInterceptor 是一个 iOS 网络请求拦截器,它可以拦截由 URLSession 和 NSURLConnection 发出的 HTTP(s) 请求。

  1. 您可以拦截一个特定的请求并返回一个新请求。
  2. 它可以拦截一个特定的请求并返回一个特定的响应和数据。
  3. 它还可以拦截一个特定的请求并回调 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文件。