Form submit via POST on Swift (NSURLSession)

POST 폼전송

NSURLSession을 통해서 POST로 폼 내용을 전송하는 예제를 작성해보겠다. 사실 이 예제는 꽤 예전에 Objective-C를 이용해서 작성해 본 바 있는 내용이다.

먼저 POST 폼 전송에 대해서 잠깐 살펴보면, 폼의 각 필드명과 필드값이 GET 방식과 비슷한 형태로 연결되고 URL인코딩을 거쳐 바이너리스트림 데이터로 생성된다. 이걸 submit 하게 되면 브라우저는 웹서버의 해당 주소에 HTTP 요청을 보내게 되는데,

  1. 메소드는 POST 로 전달
  2. 폼의 형태에 따라 Content-Type으로 전달한다. 일반 폼의 경우 application/x-www-form-urlencoded가 되며 파일 업로드의 경우에는 application/x-multipart-formdata로 전송된다.
  3. 일반 요청과 다르게 HTTP Header외에 Body 영역이 요청에 들어간다. 인코딩된 폼 데이터는 이 Body 영역에 들어가게 된다.

멀티파트 폼데이터 같은 경우에는 한 번에 여러 개의 파일을 전송할 수 있으므로 각 데이터 영역을 구분짓는 바운더리 값을 가지고 영역을 나눠주어야 하며, 각각의 파트에 해당하는 데이터의 크기도 헤더에 명시해야 한다. 하지만 여기서는 일반 폼을 제출하는 것만 고려하기로 한다.

HTTPBody에 들어가는 데이터는 , NSURLRequest 객체를 이용해서, 헤더와 폼의 내용을 인코딩해서 보낸다. 일단 결합된 폼 내용에서, 각 딜리미터를 제외한 값들은 URL 인코딩해야 하며, 최종적으로 결합된 문자열을 UTF-8로 인코딩하여 이진데이터로 만든다.

또한 이전 예제와는 달리 URLConnection 대신 URLSession을 이용하여 전송한다. 이는 무조건 비동기식으로 전송되므로, 만약 CLI 툴을 제작하는 경우에는 해당 코드를 실행한 후에 CFRunLoopRun() 함수를 호출하여 해당 비동기작업이 큐에서 종료될 때까지 프로그램이 종료되지 않고 기다리도록 해야 한다.

코드는 다음과 같다.

func URLEncode(s: String) -> String? {
    return (s as NSString).stringByAddingPercentEncodingWithAllowedCharacters(
        .URLHostAllowedCharacterSet())
}

let title: String = <# ... #>
let keyword: String = <# ... #>
let content: String = <# ... #>


let body = "title=\(URLEncode(title))&keyword=\(URLEncode(keyword))&content=\(URLEncode(content))"
let bodyData = (body as NSString).dataUsingEncoding(NSUTF8StringEncoding)

let postURL = NSURL(string:"http://w/add")!
let request = NSMutableRequest(url:postURL)
request.HTTPMethod = "POST"
request.setValue("application/x-www-form-urlencoded" forHTTPHeaderField:"Content-Type")
request.setHTTPBody(bodyData)

let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request){
    data, response, error in
    if error != nil {
        println("Fail to post content")
    } else {
        println("Successfully posted.")
    }
}
task.resume()