2016-08-05 6 views
2

生のバイトのチャンクをボディとして渡すiOS(swift3)からPOSTリクエストを行いたいと思います。私は、私は次のように働いていたと思っ作られたいくつかの実験を行っていた:私は、単一の0xF0のような単純な何かを送信しようとするまでiOS 2進体でのスウィフトポストリクエスト

let url = URL(string: "https://bla/foo/bar")! 
var request = URLRequest(url: url) 
request.httpMethod = "POST" 
request.httpBody = Data(hex: "600DF00D") 
let session = URLSession.shared 
let task = session.dataTask(with: request) { (data, response, error) in 
    "DATA \(data ?? Data()) RESPONSE \(response) ERROR \(error)".print() 
} 
task.resume() 

は、それが問題だった知りませんでした。どの時点で私の竜巻サーバーは私がそれを送っていると不平を言った

WARNING:tornado.general:Invalid x-www-form-urlencoded body: 'utf-8' codec can't decode byte 0xf0 in position 2: invalid continuation byte 

私はちょうどいくつかのヘッダーを設定すると思いますか?それとも私は何か別のものがありますか?

答えて

1

2つの一般的な解決策は次のとおりです。

  1. あなたのエラーメッセージは、Webサービスがx-www-form-urlencoded要求(例えばkey=valueを)期待しているとvalueのために、あなたはのベース64の符号化を行うことができることを教えてくれるバイナリペイロード。

    残念ながら、ベース64文字列はまだ(Webサーバは、一般的スペースとして+文字を解析するので)あなたが何かしなければならないので%は、エスケープする必要があります。

    let base64Encoded = data 
        .base64EncodedString(options: []) 
        .addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)! 
        .data(using: String.Encoding.utf8)! 
    
    var body = "key=".data(using: .utf8)! 
    body.append(base64Encoded) 
    
    var request = URLRequest(url: url) 
    request.httpBody = body 
    request.httpMethod = "POST" 
    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") 
    
    let task = URLSession.shared.dataTask(with: request) { data, response, error in 
        guard error == nil else { 
         print(error!) 
         return 
        } 
    
        ... 
    } 
    task.resume() 
    

    extension CharacterSet { 
        static let urlQueryValueAllowed: CharacterSet = { 
         let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4 
         let subDelimitersToEncode = "!$&'()*+,;=" 
    
         var allowed = CharacterSet.urlQueryAllowed 
         allowed.remove(charactersIn: generalDelimitersToEncode + subDelimitersToEncode) 
         return allowed 
        }() 
    } 
    

    その文字セットの詳細については、この回答のポイント2を参照してください:https://stackoverflow.com/a/35912606/1271826

    とにかく、これをサーバーで受け取ったら、それを元に戻してからbase-64エンコーディングを元に戻すことができます。オリジナルのバイナリペイロードがあります。

  2. また、multipart/formdataリクエスト(バイナリペイロードを提供できますが、より広範なmultipart/formdata形式の一部としてラップする必要があります)を使用できます。あなた自身でこれを行うには、https://stackoverflow.com/a/26163136/1271826を参照してください。これらのアプローチの両方のために

Alamofireのようなライブラリは、これらの要求を構築する雑草のあなたを取得し、それがさらに容易になります。

+1

Base64は本当に効率的ではありませんが、最終的にはhttp-villeのテキストストリームが決してそれほど効率的ではないと判断しました。また、バイナリデータをbase64バージョンに変換するコードは1行です。私はボディではなく、URLで使用しているので、私は逃げる必要もありません。 –

関連する問題