AFNetworkingのAFHTTPSessionManagerを使っていてBodyに素のXMLを入れてPOSTしたかったのだが、そのやり方がなかなか見当たらずソースコードを読んで解決したのでメモしておく。
ざっくり言うとAFHTTPSessionManagerでのPOSTはこんな感じに行う。
1let manager = AFHTTPSessionManager()
2manager.POST(url, parameters: params, success: { (task, response) -> Void in
3 // success
4}) { (task, error) -> Void in
5 // failure
6}
POSTするパラメータがあれば、上のメソッドのparametersのところにdictionaryとかで渡せばいいはずだが(確か)、今回やりたいのはBodyにXMLのテキストを入れるということだった。
まず気軽にparametersにXML文字列を直接渡してみようなどとやってみたら失敗した。
1let manager = AFHTTPSessionManager()
2let xmlstr = "<?xml ..."
3manager.POST(url, parameters: xmlstr, success: { (task, response) -> Void in
4 // success
5}) { (task, error) -> Void in
6 // failure
7}
これでできたリクエストを見てみるとBodyにはこんなのが入っていた。
(null)=%3C%3Fxml%20...
どうやら名前が空で値がURLエンコード済文字列のパラメータをBodyとして設定してしまっているらしい。
ソースコードを読むとそれがデフォルトの動作だということがわかった。
1// AFURLRequestSerialization.m
2switch (self.queryStringSerializationStyle) {
3 case AFHTTPRequestQueryStringDefaultStyle:
4 query = AFQueryStringFromParametersWithEncoding(parameters, self.stringEncoding);
5 break;
6}
じゃあデフォルトじゃない動作は、というと上のコードの近くにあった。
1// AFURLRequestSerialization.m
2if (self.queryStringSerialization) {
3 NSError *serializationError;
4 query = self.queryStringSerialization(request, parameters, &serializationError);
5
6 if (serializationError) {
7 if (error) {
8 *error = serializationError;
9 }
10
11 return nil;
12 }
13}
self.queryStringSerializationはBlockで、このブロックを設定してparameterのシリアライズをカスタマイズできるよ、ということのようだった。
つまり文字列をそのままBodyに入れたい場合は、
1let manager = AFHTTPSessionManager()
2let xmlstr = "<?xml ..."
3
4manager.requestSerializer.setQueryStringSerializationWithBlock { (request, params, error) -> String! in
5 return params as! String
6}
7
8manager.POST(url, parameters: xmlstr, success: { (task, response) -> Void in
9 // success
10}) { (task, error) -> Void in
11 // failure
12}
manager.requestSerializer.setQueryStringSerializationWithBlockでparameterをそのまま文字列と返してあげればよかった。
これで解決できた。良かった。
