32642


Swift 3.0にて下記curlコマンドと同等の処理を実現したいと考えておりますが、実装方法が不明のため、ご教授ください。

【実現したいコマンド】  
curl -X POST -F photo=@【画像ファイル（PNG）】 -F user_id=1 -F tag_id=1
<http://X.X.X.X/>

【具体例】  
curl -X POST -F photo=@/Users/test/test.PNG -F user_id=1 -F tag_id=1
<http://192.168.1.1/test/>

現状私が実装しているSwiftファイルは下記の通りです。

[code]

    var request = URLRequest(url:URL(string:"http://192.168.1.1/test")!)
    
    request.httpMethod = "POST"
    
    // 画像データを読み出し、Data型に変換する.
    let file: NSData = UIImagePNGRepresentation(image)! as NSData
    
    //POSTするデータを設定する
    let postString = "photo=\(file)&user_id=1&tag_id=1"
    request.httpBody = postString.data(using: .utf8)
    
    
    //タスクを作成する
    let task = URLSession.shared.dataTask(with: request, completionHandler: {
        (data, response, error) in
    
        if error != nil {
            print(error)
            return
        }
    
        print("response: \(response!)")
    
    })
    //タスクを開始する
    task.resume()
    
[/code]


CC BY-SA 3.0
2017-02-13T07:57:11.230
32627
2017-02-13T15:07:56.897
8489
question
swift swift3 curl
Swiftで「curl -F」コマンドと同等の処理を実現したい


multipart/form-data形式で作ります。  
例えばこの辺り。  
<http://qiita.com/ryokosuge/items/8ccf6be8a7575649808a>

自前で実装せずフレームワークを使えば少し簡単になります。  
例えば、  
Alamofire  
(<https://github.com/Alamofire/Alamofire>)  
APIKit  
(<https://github.com/ishkawa/APIKit>)  
など、他にも多数あります。


CC BY-SA 3.0
2017-02-13T11:43:49.157
32634
2017-02-13T11:43:49.157
8601
32627
answer


別回答にもありますが、curlの-Fオプションではデータが`multipart/form-
data`と言う形式で送信されますので、Swift側も同じことをやってやる必要があります。

  * HTTPリクエストヘッダーに`Content-Type`として`multipart/form-data`を正しく指定する
  * HTTPボディにはマルチパート形式でデータをパートごとに設定する

で、マルチパート形式の各パートは以下のようになります。(改行はCR+LF)

  1. 境界線("--"に続けてContent-Typeで指定したboundary)+改行
  2. パートヘッダー(複数行になることもある、当然各行で改行)
  3. 空行(ヘッダー部とボディ部の境目を表す)
  4. ボディ部のバイト列+改行

さらに全てのパートが終了した後、終了線を送信する必要があります。

  1. 終了線("--"に続けてContent-Typeで指定したboundary、さらに"--")

以上説明した内容をコードにすると、こんな感じになります。

[code]

    var request = URLRequest(url: URL(string: "http://192.168.1.1/test")!)
    
    request.httpMethod = "POST"
    // Content-Typeとして、multipart/form-dataを明示する、その中のboundary(境界線)の指定も必須
    let boundary = UUID().uuidString
    request.addValue("multipart/form-data; boundary=\"\(boundary)\"", forHTTPHeaderField: "Content-Type")
    
    // 画像データを読み出し、Data型に変換する.
    let file = UIImagePNGRepresentation(image)!
    
    //POSTするデータを設定する
    var postData = Data()
    //画像データ用のパートデータを追加する
    postData.append("--\(boundary)\r\n".data(using: .utf8)!) //パートの境界線、先頭にも必要
    postData.append("Content-Disposition: form-data; name=\"photo\"; filename=\"test.PNG\"\r\n".data(using: .utf8)!) //パートヘッダーとしてContent-Dispositionと
    postData.append("Content-Type: image/png\r\n".data(using: .utf8)!) //Content-Typeを指定する
    postData.append("\r\n".data(using: .utf8)!) //空行がパートヘッダーとパートボディの境界線
    postData.append(file) //パートボディとして画像をData化したものを追加する
    postData.append("\r\n".data(using: .utf8)!) //パートボディの終了
    
    //文字データ(user_id)用のパートを追加する
    postData.append("--\(boundary)\r\n".data(using: .utf8)!) //パートの境界線
    postData.append("Content-Disposition: form-data; name=\"user_id\"\"\r\n".data(using: .utf8)!) //文字データの送信の場合(普通は)Content-Typeはなくてもサーバは受信してくれる
    postData.append("\r\n".data(using: .utf8)!) //空行がパートヘッダーとパートボディの境界線
    postData.append("1".data(using: .utf8)!) //パートボディとしてテキストをData化したものを追加する
    postData.append("\r\n".data(using: .utf8)!) //パートボディの終了
    
    //文字データ(tag_id)用のパートを追加する
    postData.append("--\(boundary)\r\n".data(using: .utf8)!) //パートの境界線
    postData.append("Content-Disposition: form-data; name=\"tag_id\"\"\r\n".data(using: .utf8)!)
    postData.append("\r\n".data(using: .utf8)!) //空行がパートヘッダーとパートボディの境界線
    postData.append("1".data(using: .utf8)!) //パートボディとしてテキストをData化したものを追加する
    postData.append("\r\n".data(using: .utf8)!) //パートボディの終了
    
    //全パートの終了を示す
    postData.append("--\(boundary)--".data(using: .utf8)!) // end of all parts
    
    request.httpBody = postData
    
[/code]

(上記のように作った`request`の使い方はGETや単純なPOSTと同じ。)

* * *

少し大変に感じるでしょうか。私も普通のPOSTリクエストの送信くらいなら、「サードパーティのフレームワークなんて要らない」とか言い出す方ですが、`multipart/form-
data`は、少し敷居が高いので、フレームワーク的なものを使った方が良いかもしれません。


CC BY-SA 3.0
2017-02-13T15:07:56.897
32642
2017-02-13T15:07:56.897
13972
32627
answer