iOS如何为每个UIWebView请求添加cookie?

时间:2018-01-17 06:40:06

标签: ios swift cookies uiwebview

我需要在UIWebView中使用Angular打开网址,我需要为每个UIWebView请求发送Cookie。

我试图做的事情:

我试图检查请求是否包含cookie。如果它UIWebView执行请求,如果不是,我创建相同的请求,但使用cookie并执行它。要替换请求,我使用了UIWebViewDelegate方法func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool。但它不像我预期的那样工作,有些请求没有cookie。

我的代码:

final class FieldServiceViewController: UIViewController {

    private var webView = UIWebView()
    private var sessionID = String()

    override func viewDidLoad() {
        super.viewDidLoad()

        _ = JSONAPI.getSessionID().subscribe(onNext: { [weak self] sessionID in
            self?.sessionID = sessionID
            self?.configureUI()
            let string = "https://someURL"
            let url = URL(string: string)
            let request = URLRequest(url: url!)
            self?.webView.loadRequest(request)
        })
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        webView.frame = view.bounds
    }

    private func configureUI() {
        webView.delegate = self
        view.addSubview(webView)
    }

    private func cookedRequest(from: URLRequest) -> URLRequest? {

        let cookiesKey = "Cookie"
        let headers = from.allHTTPHeaderFields ?? [:]
        if (headers.contains { $0.0 == cookiesKey }) {
            return nil
        }

        var request = from
        request.cachePolicy = .reloadIgnoringLocalAndRemoteCacheData
        let cookiesToAdd = "SESSIONID=\(sessionID)"
        request.addValue(cookiesToAdd, forHTTPHeaderField: cookiesKey)
        return request
        }
    }

    extension FieldServiceViewController: UIWebViewDelegate {

    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {

        if let cooked = cookedRequest(from: request) {
            webView.loadRequest(cooked)
            return false
        }

        return true
    }
}

如何为每个UIWebView请求添加cookie?

P.S。我还在HTTPCookieStorage中保存了Cookie,但看起来UIWebView的请求与共享存储之间没有关联。

3 个答案:

答案 0 :(得分:4)

我希望WKWebView代替UIWebView,因为UIWebView是deprecated

  

现在关于将会话ID添加到Angular发出的每个请求中   项目

我建议您不要通过委托方法创建新请求来添加会话ID,而是建议在Angular级别添加request interceptor,这样您就可以更好地控制Angular项目发出的每个请求。

通过匿名工厂

注册拦截器
$httpProvider.interceptors.push(function($q, dependency1, dependency2) {
  return {
   'request': function(config) {
       config.headers['SESSIONID'] = 'Your Session id here';
    },

    'response': function(response) {

    }
  };
});
  

现在你可以如何使用它。

您可以将上面的代码转换为Swift String,当您拥有会话ID并加载Angular项目时,您可以通过wkwebview的evaluatejavaScript方法执行此操作。

e.g。

var sessionId = "you id"
        var s="\n" +
        " $httpProvider.interceptors.push(function($q, dependency1, dependency2) {\n" +
        " return {\n" +
        " \'request\': function(config) {\n" +
        " config.headers[\'SESSIONID\'] = \'\(sessionId)\';\n" +
        " },\n" +
        " \n" +
        " \'response\': function(response) {\n" +
        " \n" +
        " }\n" +
        " };\n" +
        " });"

        webView.evaluateJavaScript(s, completionHandler: {(message,error) in
            print(error ?? "No Error")
        })

答案 1 :(得分:3)

您可以将代码更改为:

func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
    if request.allHTTPHeaderFields?["SESSIONID"] == nil {
       var request: URLRequest = request
       request.allHTTPHeaderFields?["SESSIONID"] = "your_session_id"
       webView.loadRequest(request)
       return false
    }
    return true
}

<强>更新

正如我所知,解决问题的最佳方法是使用URLProtocol拦截您的请求。 创建下一个类:

class MyURLProtocol: URLProtocol, NSURLConnectionDelegate, NSURLConnectionDataDelegate {

    static let protocolKey = "MyURLProtocolKey"

    private var connection: NSURLConnection?

    override class func canInit(with request: URLRequest) -> Bool {
        if let isCustom = URLProtocol.property(forKey: MyURLProtocol.protocolKey, in: request) as? Bool{
            return false
        }
        return true
    }

    override class func canonicalRequest(for request: URLRequest) -> URLRequest {
        //You can add headers here
        var request = request
        print("request: \(request.url?.absoluteString ?? " ")")
        request.allHTTPHeaderFields?["SESSION_ID"] = "your_session_id"
        return request
    }

    override class func requestIsCacheEquivalent(_ a: URLRequest, to b: URLRequest) -> Bool {
        return super.requestIsCacheEquivalent(a, to: b)
    }

    override func startLoading() {
        let newRequest: NSMutableURLRequest = self.request as! NSMutableURLRequest
        URLProtocol.setProperty(true, forKey: MyURLProtocol.protocolKey, in: newRequest)
        self.connection = NSURLConnection(request: newRequest as URLRequest, delegate: self, startImmediately: true)
    }

    override func stopLoading() {
        self.connection?.cancel()
        self.connection = nil
    }

    //MARK: NSURLConnectionDataDelegate methods
    func connection(_ connection: NSURLConnection, didReceive response: URLResponse) {
        self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
    }

    func connection(_ connection: NSURLConnection, didReceive data: Data) {
         self.client?.urlProtocol(self, didLoad: data as Data)
    }

    func connectionDidFinishLoading(_ connection: NSURLConnection) {
        self.client?.urlProtocolDidFinishLoading(self)
    }

    func connection(_ connection: NSURLConnection, didFailWithError error: Error) {
        self.client?.urlProtocol(self, didFailWithError: error)
    }
}

现在在AppDelegate

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    URLProtocol.registerClass(MyURLProtocol.self)
    return true
}

答案 2 :(得分:1)

感谢您的帮助。通过创建具有特定域的cookie来解决问题:

final class FieldServiceViewController: UIViewController, DLHasHomeTitleView {

    private let fieldServiceEndPoint = Bundle.main.object(forInfoDictionaryKey: "FIELD_SERVICE_ENDPOINT") as! String

    private var webView = UIWebView()
    private var sessionID = String()

    override func viewDidLoad() {
        super.viewDidLoad()

        configureUI()

        _ = JSONAPI.getSessionID().subscribe(onNext: { [weak self] sessionID in
            guard let `self` = self else { return }

            self.sessionID = sessionID

            let urlString = "https://\(self.fieldServiceEndPoint)"
            let url = URL(string: urlString)
            let request = URLRequest(url: url!)

            let cookie = HTTPCookie(properties: [
                .name: "JSESSIONID",
                .value: sessionID,
                .path: "/",
                .domain: self.fieldServiceEndPoint])
            HTTPCookieStorage.shared.setCookie(cookie!)

            self.webView.loadRequest(request)
        })
    }