【问题标题】:iOS How to add cookie to each UIWebView request?iOS 如何为每个 UIWebView 请求添加 cookie?
【发布时间】:2018-01-17 06:40:06
【问题描述】:

我需要在 UIWebView 中使用 Angular 打开 URL,并且我需要在每个 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?

附:我还在HTTPCookieStorage中保存了cookie,但看起来UIWebView的请求和共享存储之间根本没有联系。

【问题讨论】:

    标签: ios swift cookies uiwebview


    【解决方案1】:

    我更喜欢 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 字符串,当您拥有会话 ID 并加载 Angular 项目时,您可以通过 wkwebview 的 evaluatejavaScript 方法执行此操作。

    例如

    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")
            })
    

    【讨论】:

    • 感谢您的回答。我尝试了您的解决方案,但现在我得到了白屏。页面根本不加载
    • webView.evaluateJavaScript() 返回错误:Error Domain=WKErrorDomain Code=4 "A JavaScript exception occurred" UserInfo={WKJavaScriptExceptionLineNumber=2, WKJavaScriptExceptionMessage=ReferenceError: Can't find variable: $httpProvider, WKJavaScriptExceptionColumnNumber=15, WKJavaScriptExceptionSourceURL=about:blank, NSLocalizedDescription=A JavaScript exception occurred}
    • @BadCodeDeveloper 您需要在加载 Angular 项目后执行此操作
    【解决方案2】:

    您可以将代码更改为:

    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
    }
    

    【讨论】:

    • 感谢您的回答,但它的工作原理相同。一些请求在没有 cookie 的情况下执行
    • @BadCodeDeveloper 你能检查一下带cookie和不带cookie的btw请求有什么区别吗?
    • Angular 执行的请求没有 cookie。这就是我能看到的所有差异
    【解决方案3】:

    感谢您的帮助。通过创建具有特定域的 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)
            })
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-25
      • 2020-03-09
      • 2012-06-07
      • 2021-02-09
      • 1970-01-01
      相关资源
      最近更新 更多