Swift:如何记住cookie以获取更多的http请求

时间:2015-07-16 21:22:48

标签: ios swift cookies ios9

我正在处理登录应用程序。成功登录后,响应cookie数据 如何为将来的请求使用/保存此数据?
对于初学者,我试图将其保存在NSHTTPCookieStorage中。但这也行不通。
登录方式(部分):

let task = session.dataTaskWithRequest(request) { (data, responseData, error) -> Void in
            if let response = responseData as? NSHTTPURLResponse {
                statusCode = response.statusCode
                print("Response code: \(statusCode)")
            }

            var json: NSDictionary?
            do {
                json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves) as? NSDictionary
            } catch {
                print(error)
                err = error
            }

            if(statusCode != 200) {

                let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
                print("Error could not parse JSON: '\(jsonStr)'")
            }
            else {

                print("Everything Looks good: \(responseData)")
                self.setCookies(responseData!)
                self.shouldPerformSegueWithIdentifier("showHomeController", sender: self)

            }
        }

        task?.resume()

保存Cookie方法

private func setCookies(response: NSURLResponse) {
        if let httpResponse = response as? NSHTTPURLResponse {
            let cookies = NSHTTPCookie.cookiesWithResponseHeaderFields(httpResponse.allHeaderFields, forURL: response.URL!) as! [NSHTTPCookie]
            NSHTTPCookieStorage.sharedHTTPCookieStorage().setCookies(cookies, forURL: response.URL!, mainDocumentURL: nil)
            for cookie in cookies {
                var cookieProperties = [String: AnyObject]()
                cookieProperties[NSHTTPCookieName] = cookie.name
                cookieProperties[NSHTTPCookieValue] = cookie.value()
                cookieProperties[NSHTTPCookieDomain] = cookie.domain
                cookieProperties[NSHTTPCookiePath] = cookie.path
                cookieProperties[NSHTTPCookieVersion] = NSNumber(integer: cookie.version)
                cookieProperties[NSHTTPCookieExpires] = NSDate().dateByAddingTimeInterval(31536000)

                let newCookie = NSHTTPCookie(properties: cookieProperties)
                NSHTTPCookieStorage.sharedHTTPCookieStorage().setCookie(newCookie!)

                println("name: \(cookie.name) value: \(cookie.value())")
            }
        }
    }

错误:

Cannot invoke 'cookiesWithResponseHeaderFields' with an argument list of type '([NSObject : AnyObject], forURL: NSURL)'

3 个答案:

答案 0 :(得分:24)

如果您意识到cookie的使用,服务器必须发送标头Set-Cookie以响应客户端请求。只需检查标题作为响应,您将看到Set-Cookie标题字段,其中包含Cookie。

https://en.wikipedia.org/wiki/HTTP_cookie#Setting_a_cookie

如果您使用默认或背景URLSessionConfiguration的URLSession,则无需进行任何更改以保存Cookie。如果您查看默认URLSessionConfiguration的文档,其描述如下,

  

默认会话配置使用基于磁盘的持久缓存   (除非将结果下载到文件中)并存储   用户钥匙串中的凭据。它还存储cookie(通过   默认情况下)与NSURLConnection和。相同的共享cookie存储区   NSURLDownload类。

此外,您可以在财产URLSessionConfiguration herehttpCookieStorage文档中进一步了解相关内容。

这是一小段代码,我将进一步用它来测试cookie存储。

let sessionConfiguration = URLSessionConfiguration.ephemeral
sessionConfiguration.httpCookieAcceptPolicy = .never
let customSession = URLSession(configuration: sessionConfiguration)

enum Result {
    case success(HTTPURLResponse, Data)
    case failure(Error)
}

func readCookie(forURL url: URL) -> [HTTPCookie] {
    let cookieStorage = HTTPCookieStorage.shared
    let cookies = cookieStorage.cookies(for: url) ?? []
    return cookies
}

func deleteCookies(forURL url: URL) {
    let cookieStorage = HTTPCookieStorage.shared

    for cookie in readCookie(forURL: url) {
        cookieStorage.deleteCookie(cookie)
    }
}

func storeCookies(_ cookies: [HTTPCookie], forURL url: URL) {
    let cookieStorage = HTTPCookieStorage.shared
    cookieStorage.setCookies(cookies,
                             for: url,
                             mainDocumentURL: nil)
}


func executeURLRequest(url: URL, inSession session: URLSession = .shared, completion: @escaping (Result) -> Void) {
    let task = session.dataTask(with: url) { data, response, error in

        if let response = response as? HTTPURLResponse,
            let data = data {
            completion(.success(response, data))
            return
        }

        if let error = error {
            completion(.failure(error))
            return
        }

        let error = NSError(domain: "com.cookiesetting.test", code: 101, userInfo: [NSLocalizedDescriptionKey: "Unknown error occurred"])
        completion(.failure(error))
    }
    task.resume()
}

使用上面的代码段,我们首先测试默认会话是否保存了Cookie。

var cookies = readCookie(forURL: googleURL)
print("Cookies before request: ", cookies)

executeURLRequest(url: googleURL) { result in
    if case .success (let data) = result {
        cookies = readCookie(forURL: googleURL)
        print("Cookies after request: ", cookies)

        deleteCookies(forURL: googleURL)
        cookies = readCookie(forURL: googleURL)
        print("Cookies after deletion: ", cookies)
    }
}

而且,这就是我们得到的,

Cookies before request:  []
Cookies after request:  [<NSHTTPCookie
    version:0
    name:1P_JAR
    value:2018-09-26-15
    expiresDate:'2018-10-26 15:39:46 +0000'
    created:'2018-09-26 15:39:46 +0000'
    sessionOnly:FALSE
    domain:.google.com
    partition:none
    sameSite:none
    path:/
    isSecure:FALSE
 path:"/" isSecure:FALSE>, <NSHTTPCookie
    version:0
    name:NID
    value:139=E3g4bKNRGcYoeFuaECpfsx_Efp64xONmVwcJS7f7PuZe8LayS5ZkGuz3f7z6eq7zoBm2z-opTvzX8YPzn8v1ebjH6iyt5-6yDYm9RE6XhXwHCZWs98_j7nb11u2EPnHI
    expiresDate:'2019-03-28 15:39:46 +0000'
    created:'2018-09-26 15:39:46 +0000'
    sessionOnly:FALSE
    domain:.google.com
    partition:none
    sameSite:none
    path:/
    isSecure:FALSE
    isHTTPOnly: YES
 path:"/" isSecure:FALSE isHTTPOnly: YES>]
Cookies after deletion:  []

URLSessionConfiguration还有一个属性httpCookieAcceptPolicy,引用以下内容:

  

此属性确定其中所有任务的cookie接受策略   基于此配置的会话。

     

默认值为   HTTPCookie.AcceptPolicy.onlyFromMainDocumentDomain。你可以改变它   到HTTPCookie.AcceptPolicy中定义的任何常量   枚举类型。

     

如果您想更直接地控制接受哪些Cookie,请设置   这个值为HTTPCookie.AcceptPolicy.never然后使用   allHeaderFields和cookies(withResponseHeaderFields:for :)方法   自己从URL响应对象中提取cookie。

因此,如果您希望自己操纵Cookie,可以将httpCookieAcceptPolicy设置为never

以下代码显示,从未使用httpCookieAcceptPolicy时未存储Cookie

var cookies = readCookie(forURL: googleURL)
print("Cookies before request: ", cookies)

executeURLRequest(url: googleURL, inSession: customSession) { result in
    if case .success (let data) = result {
        cookies = readCookie(forURL: googleURL)
        print("Cookies after request: ", cookies)

    }
}

记录以下内容;

Cookies before request:  []
Cookies after request:  []

您可以看到使用.never for httpCookieStoragePolicy,系统不会将cookie存储到共享cookie存储。

你也可以自己存储cookie,看起来像这样,

自行存储Cookie

deleteCookies(forURL: googleURL)
var cookies = readCookie(forURL: googleURL)
print("Cookies before request: ", cookies)
executeURLRequest(url: googleURL, inSession: customSession) { result in
    if  case let .success  (response, data) = result {
        guard let cookiesResponseHeader = response.allHeaderFields["Set-Cookie"] else {
            return
        }

        cookies = readCookie(forURL: googleURL)
        print("Cookies after request: ", cookies)

        let responseCookies = HTTPCookie.cookies(withResponseHeaderFields: response.allHeaderFields as! [String: String], for: googleURL)
        storeCookies(responseCookies, forURL: googleURL)
        cookies = readCookie(forURL: googleURL)
        print("Cookies after storing: ", cookies)

    }
}

以下是上面代码打印到控制台的内容,

Cookies before request:  []
Cookies after request:  []
Cookies after storing:  [<NSHTTPCookie
    version:0
    name:1P_JAR
    value:2018-09-26-18
    expiresDate:'2018-10-26 18:35:23 +0000'
    created:'2018-09-26 18:35:23 +0000'
    sessionOnly:FALSE
    domain:.google.com
    partition:none
    sameSite:none
    path:/
    isSecure:FALSE
 path:"/" isSecure:FALSE>, <NSHTTPCookie
    version:0
    name:NID
    value:139=D7GTUazWfeaB5Bcu1wN5I_Il2k6xALNiRZDX_DN9totQbnrP31gE0GzlsjCHDISUv8ulPq9G8Yu1p-GsZcVRw2fnrBROih-vtAVBic5UXFKUkG_ZbFQYKFprr4MPHDGS
    expiresDate:'2019-03-28 18:35:23 +0000'
    created:'2018-09-26 18:35:23 +0000'
    sessionOnly:FALSE
    domain:.google.com
    partition:none
    sameSite:none
    path:/
    isSecure:FALSE
    isHTTPOnly: YES
 path:"/" isSecure:FALSE isHTTPOnly: YES>]

上面的代码使用.never HTTPCookieAcceptPolicy到URLSessionConfiguration,但我们从响应中创建cookie并自己将它存储到cookie存储区。

答案 1 :(得分:1)

  

class func cookiesWithResponseHeaderFields(_ headerFields:[String:   字符串],forURL网址:NSURL) - &gt; [NSHTTPCookie]

请注意,headerFields是[String:String] Dictionary,编译器抱怨你正在传递[NSObject:AnyObject]

答案 2 :(得分:-1)

对于URLSession连接,您可以使用此功能(在收到第一个回复后):

var cookies =  URLSession.shared.configuration.httpCookieStorage?.cookies

你可以像这样使用这些cookie:

var session = URLSession.self
session.shared.configuration.httpCookieStorage?.setCookies(cookies, for: baseurl, mainDocumentURL: baseurl)
    let task = session.shared.dataTask(with: url)