10

AlamofireマネージャーインスタンスにCookieを自動的に記憶させて設定させようとしていますが、失敗した試みは次のとおりです:

let cfg = NSURLSessionConfiguration.defaultSessionConfiguration()
let cooks = NSHTTPCookieStorage.sharedHTTPCookieStorage()

// makes no difference whether it's set or left at default
cfg.HTTPCookieStorage = cooks
cfg.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicy.Always

let mgr = Alamofire.Manager(configuration: cfg)

mgr.request(NSURLRequest(URL: NSURL(string: "http://httpbin.org/cookies/set?stack=overflow"))).responseString {
    (_, _, response, _) in
    var resp = response // { "cookies": { "stack": "overflow" } }
    // becomes empty if cfg.HTTPCookieStorage set to nil
}

mgr.request(NSURLRequest(URL: NSURL(string: "http://httpbin.org/cookies"))).responseString {
    (_, _, response, _) in
    var resp = response // { "cookies": {} }
    // always empty no matter what
}

cooks.cookiesForURL(NSURL(string: "http://httpbin.org/cookies")) // 0 elements

最初の URL はヘッダーを送信し、次に ( 2 番目の URL に相当するSet-Cookie : stack=overflow; Path=/) にリダイレクト (302) します。/cookiesこれは私のブラウザでは問題なく動作するので (最初の URL にアクセスすると、2 番目の URL には常にその Cookie が表示されます)、Alamofire でその動作を再現したいと考えています。

4

1 に答える 1

19

コードはすべて正常に動作しています。リクエストを行うときに非同期メソッドを呼び出していることを考慮していないだけです。そのコードが実行されると、次のようになります。 を呼び出すたびにmgr.request(...)、上記のすべてのコードが実行されるまで解決されない新しい非同期呼び出しが開始されます。

| configure mgr
|
| request /cookies/set?... ----
|                              \
| request /cookies ----        |
|                      \       |
| cookiesForUrl()      |       |
|                      |       |
| [function returns]   |       |
                       |       |
...time passes...      |       |
                       /       |
  /cookies handler ----        |
                               |
...more time...                |
                               /
  /cookies/set? handler -------

(これらの最後の 2 つのハンドラーの順序は不定です - サーバー/トラフィックなどに依存します)。

したがって、「http://httpbin.org/cookies」へのリクエストには、実際には Cookie が含まれていません。これは、Cookie を設定するリクエストが 1 命令前に送信されただけだからです。Cookie を表示するには、最初の呼び出しが戻って次の要求を送信するまで待つ必要があります。UIViewControllerサブクラスでラップしました:

class CookieViewController: UIViewController {
    // mgr needs to still exist when the response handlers are called
    var mgr: Alamofire.Manager!
    let cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage()

    func configureManager() -> Alamofire.Manager {
        let cfg = NSURLSessionConfiguration.defaultSessionConfiguration()
        cfg.HTTPCookieStorage = cookies
        return Alamofire.Manager(configuration: cfg)
    }

    func setCookies() {
        mgr.request(NSURLRequest(URL: NSURL(string: "http://httpbin.org/cookies/set?stack=overflow")!)).responseString {
            (_, _, response, _) in
            var resp = response // { "cookies": { "stack": "overflow" } }
            println(resp)

            // the cookies are now a part of the URLSession - 
            // we can inspect them and call the next URL
            println(self.cookies.cookiesForURL(NSURL(string: "http://httpbin.org/cookies")!))
            self.checkCookies()
        }
    }

    func checkCookies() {
        mgr.request(NSURLRequest(URL: NSURL(string: "http://httpbin.org/cookies")!)).responseString {
            (_, _, response, _) in
            var resp = response // { "cookies": { "stack": "overflow" } }
            println(resp)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        mgr = configureManager()
        setCookies()
    }
}
于 2014-11-01T15:23:45.373 に答える