読者です 読者をやめる 読者になる 読者になる

DRYな備忘録

Don't Repeat Yourself.

AlamofireでRequestのHeaderにContent-Type: application/jsonを追加したいのにいっこうに"text/plain"になってしまう問題

問題

f:id:otiai10:20160712215056p:plain

そりゃ400だろ、って感じ。curl使って-H "Content-Type: application/json"ではちゃんとサーバからレスポンスあるのは確認済み。

やったこと1 : Alamofire.Manager.requestの第3引数にheadersを食わせる

let headers = [
    "Content-Type": "application/json"
]
// self.manager == Alamofire.Manager
self.manager?
    .request(.POST, url, parameters: params, headers: headers)

やったこと2 : Alamofire.Managerのインスタンス初期化時のconfigにContent-Typeを設定

// Singleton Accessor
static var manager: Alamofire.Manager? {
    if let _ = _manager {
        return _manager
    }
    let config = NSURLSessionConfiguration.defaultSessionConfiguration()
    config.HTTPAdditionalHeaders?.updateValue("application/json", forKey: "Content-Type")
    _manager = Alamofire.Manager(configuration: config)
    return _manager
}

やったこと3 : インスタンスのsession.configurationにHTTPAdditionalHeadersを設定

self.manager?.session.configuration.HTTPAdditionalHeaders = [
    "Content-Type": "application/json"
]
self.manager?

やったこと4 : NSMutableURLRequestをつかって全部ひとつのオブジェクトにぶっこむ

let req = NSMutableURLRequest(URL: url)
req.HTTPMethod = "POST"
req.setValue("application/json", forHTTPHeaderField: "Content-Type")
req.HTTPBody = NSKeyedArchiver.archivedDataWithRootObject(params!)
        
self.manager?
    .request(req)

結論: Content-Typeはapplication/jsonなんだけど、paramsをJSON文字列エンコーディングできてなかったので、勝手にサーバがtext/plainとして解釈してた

実際に送られているrequestのheaderを見る

  • ローカルプロキシで実際に送られているRequest Headerを見れていると思ってたんだけど、なんだかんだで違ったっぽい
  • クライアントアプリケーション側で実際に送られたRequest HeaderをSwfitでデバッグする
self.manager?
    .request(
        method, url, parameters: params, headers: headers
    )
    .response { request, response, data, error -> Void in
        print(request?.valueForHTTPHeaderField("Content-Type"))
        print(NSString(data: (request?.HTTPBody)!, encoding: NSUTF8StringEncoding))
    }

その出力

Optional("application/json")
Optional(project=123&status=0&username=otiai10)

RequestのContent-Typeはapplication/jsonが行ってるけど、paramsがURL encodedに見える

Alamofireでapplication/jsonなparamsをJSON string encodedでちゃんと送る

self.manager?
    .request(
-        method, url, parameters: params, headers: headers
+        method, url, parameters: params, headers: headers,
+        encoding: Alamofire.ParameterEncoding.JSON
    )
    .response { request, response, data, error -> Void in
        print(request?.valueForHTTPHeaderField("Content-Type"))
        print(NSString(data: (request?.HTTPBody)!, encoding: NSUTF8StringEncoding))
    }

その出力

Optional("application/json")
Optional({"project":123,"status":0,"username":"otiai10"})

ローカルプロキシでもちゃんとapplication/jsonを送って200を受けているのがわかる

f:id:otiai10:20160717163233p:plain

DRYな備忘録として