由 base64encodeString 组成的 NSMutableRequest 的主体在作为字符串发送时被截断 [英] Body of NSMutableRequest consisting of base64encodeString gets truncated while sending as a string

查看:54
本文介绍了由 base64encodeString 组成的 NSMutableRequest 的主体在作为字符串发送时被截断的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近,我在做一个 NSUrlSession 任务来上传多张图片到后端.我将所有图像以 .png 表示形式附加到一个数组中.我将整个数组转换为 base64 字符串格式,并尝试将整个主体作为字符串发送.

Recently, I am doing a NSUrlSession task to upload multiple images to the backend . I appended all the images in .png representation in an array. I converted the whole array into a base64 String format and tried to send the whole body as a string.

imageArray 到 String 的转换 -

let imageArrayData: NSData = NSKeyedArchiver.archivedDataWithRootObject(imageArray)
        let imageArrayBase64String = imageArrayData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))

这里打印数组,我得到 -

<代码>(字符串)imageArrayBase64String =YnBsaXN0MDDUAQIDBAUIIiNUJHRvcFgkb2JqZWN0c1gkdmVyc2lvblkkYXJjaGl2ZXLRBgdUcm9vdIABpQkKEBQcVSRudWxs0gsMDQ5WJGNsYXNzWk5TLm9iamVjdHOABKEPgALSEQsSE1dOUy5kYXRhTxIBe8QxiVBORw0KGgoAAAANSUhEUgAAEMAAAAsgCAIAAABnC3DjAAABGWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGBSSCwoyGESYGDIzSspCnJ3UoiIjFJgf8DAzCDDwMUgwGCUmFxc4BgQ4MMABDAaFXy7xsAIoi/rgszClMcLuFJSi5OB9B8gzk4uKCphYGDMALKVy0sKQOweIFskKRvMXgBiFwEdCGRvAbHTIewTYDUQ9h2wmpAgZyD7A5DNlwRmM4Hs4kuHsAVAbKi9ICDomJKflKoA8r2GoaWlhSaJfiAISlIrSkC0c35BZVFmekaJgiMwpFIVPPOS9XQUjAwMzRgYQOEOUf05EByejGJnEGIIgBCbI8HA4L + UgYHlD0LMpJeBYYEOAwP/VISYmiEDg4A + A8O + OcmlRWVQYxiZjBkYCPEBNDZKYi1QenUAAAAcaURPVAAAAAIAAAAAAAAFkAAAACgAAAWQAAAFkADAfM/Go8QlAABAAElEQVR4AXS8BXQcV7b3K0Pm3jt3IIlBlmzLFjMzMzMztVhqUasZ1ChmZibLsixmmSmGkB1yzIyhgZubTGJ//+ rK6GW97721/muvffbZdaqqq7vqVNX + tUJijjZEKTBIztNNyNZKoeol5WlB8dnqibmaKfk68BOy1JNztVKpOkk5mgiSItPkPjLVU/K14rIOpxboJlO1YzNVE3I0IDJzayiMhmBclhoisEhOK9JHPhZPytNILdCiFGqn07STqKrJVI2UfM24rEPx2YcRzKDppRZoYxWkknM1IGxPSp52cp56epFOar5mClUjmYoN1kor0kVyWpFOejHG18E4KQXqqYUaacUaGSVa2XSdPJY+pUAtk6aVxdB"

创建主体 -

let body = "task=doNotification&select_category=\(selectCategory!)&select_type=\(selectType!)&class=\(classid!)&repliable=\(repliable)&select_students=\(selectedStudents)&select_group=\(selectGroup!)&title=\(SbjctOrTtlTxtFld.text!)&text=\(textVieww.text!)&image=\(imageArrayBase64String)&date=\(dateText!)&time=\(timeText!)"

在这里打印正文,我得到 -

(String) body = "task=doNotification&select_category=exams&select_type=check&class=2&repliable=1&select_students=(\n    26,\n    25\n)&select_group=11&title=self&text=Adam <IMG_0002>&image=YnBsaXN0MDDUAQIDBAUIIiNUJHRvcFgkb2JqZWN0c1gkdmVyc2lvblkkYXJjaGl2ZXLRBgdUcm9vdIABpQkKEBQcVSRudWxs0gsMDQ5WJGNsYXNzWk5TLm9iamVjdHOABKEPgALSEQsSE1dOUy5kYXRhTxIBe8QxiVBORw0KGgoAAAANSUhEUgAAEMAAAAsgCAIAAABnC3DjAAABGWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGBSSCwoyGESYGDIzSspCnJ3UoiIjFJgf8DAzCDDwMUgwGCUmFxc4BgQ4MMABDAaFXy7xsAIoi/rgszClMcLuFJSi5OB9B8gzk4uKCphYGDMALKVy0sKQOweIFskKRvMXgBiFwEdCGRvAbHTIewTYDUQ9h2wmpAgZyD7A5DNlwRmM4Hs4kuHsAVAbKi9ICDomJKflKoA8r2GoaWlhSaJfiAISlIrSkC0c35BZVFmekaJgiMwpFIVPPOS9XQUjAwMzRgYQOEOUf05EByejGJnEGIIgBCbI8HA4L+UgYHlD0LMpJeBYYEOAwP/VISYmiEDg4A+A8O+OcmlRWVQYxiZjBkYCPEBNDZKYi1QenUAAAAcaURPVAAAAAIAAAAAAAAFkAAAACgAAAWQAAAFkADAfM/Go8QlAABAAElEQVR4AXS8BXQcV7b3K0Pm3jt3IIlBlmzLFjMzMzMztVhqUasZ1ChmZibLsixmmSmGkB1yzIyhgZubTGJ//+rK6GW97721/muvffbZdaqqq7vqVNX+tUJijjZEKTBIztNNyNZKoeol5WlB8dnqibmaKfk68BOy1JNztVKpOkk5mgiSItPkPjLVU/K14rIOpxboJlO1YzN"

正如您所注意到的,主体甚至没有传递数组的完整编码字符串,也没有传递最后 2 个参数,即 date &时间.

为什么会这样?

调用网络服务 -

func sendAPIRequest(urlpath:NSString,body: NSString , completion: (result: NSMutableDictionary, error: AnyObject?)-> Void ) -> Void
    {

        let url:NSURL = NSURL(string: urlpath as String)!

        let request = NSMutableURLRequest(URL: url)
        request.HTTPMethod = "POST"

        let bodydata = body.dataUsingEncoding(NSUTF8StringEncoding)
        request.HTTPBody = bodydata



        let config = NSURLSessionConfiguration.defaultSessionConfiguration()
        let session = NSURLSession(configuration: config)

        let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in

            do
            {

                let resultdic = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSMutableDictionary
                //print(resultdic!)
                completion(result: resultdic!,error: nil)


            }
            catch
            {
              print("error")
            }

        }
        task.resume()

推荐答案

几点意见:

  1. 看起来您正在调试器中查看 body.这将截断字符串(尽管通常在末尾显示省略号以表明它已被截断).我建议你试试 print(body) 看看你是否在那里看到了整个字符串.

  1. It looks like you're looking at body in the debugger. That will truncate the string (though usually it shows ellipses at the end to indicate that it was truncated). I'd suggest you try print(body) and see if you see the whole string there.

您的 selectStudents 是一个 NSArray,当您对其进行字符串插值时,它会在其中包含一个换行符.最终效果是这个 x-www-form-urlencoded 请求格式不正确,很可能会被服务器拒绝.有几种方法可以解决这个问题

Your selectStudents is an NSArray and when you do string interpolation on that, it includes a newline character in it. The net effect is that this x-www-form-urlencoded request is not well-formed and will likely be rejected by the server. There are a couple of ways of resolving with this

  • 如果您的服务器真的需要 select_students=(\n 26,\n 25\n) 形式的字符串(如果这真的是您想要的,我会非常惊讶)想要),您将百分比转义该字符串:

  • If your server is really expecting a string of the form select_students=(\n 26,\n 25\n) (which I'd be very surprised if that's really what you want), you'd percent escape that string:

let selectedStudentsString = "selectedStudents=\(selectedStudents)".stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryParameterAllowedCharacterSet())!

这将产生:

selectedStudents=(%0A%20%20%20%20foo,%0A%20%20%20%20bar%0A)

其中 URLQueryParameterAllowedCharacterSet 定义为:

extension NSCharacterSet {

    /// Returns the character set for characters allowed in the individual parameters within a query URL component.
    ///
    /// The query component of a URL is the component immediately following a question mark (?).
    /// For example, in the URL `http://www.example.com/index.php?key1=value1#jumpLink`, the query
    /// component is `key1=value1`. The individual parameters of that query would be the key `key1`
    /// and its associated value `value1`.
    ///
    /// According to RFC 3986, the set of unreserved characters includes
    ///
    /// `ALPHA / DIGIT / "-" / "." / "_" / "~"`
    ///
    /// In section 3.4 of the RFC, it further recommends adding `/` and `?` to the list of unescaped characters
    /// for the sake of compatibility with some erroneous implementations, so this routine also allows those
    /// to pass unescaped.


    class func URLQueryParameterAllowedCharacterSet() -> Self {
        return self.init(charactersInString: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~/?")
    }

}

请参阅 https://stackoverflow.com/a/35912606/1271826 了解替代百分比转义选项.但避免将 stringByAddingPercentEncodingWithAllowedCharacters 与任何现有字符集(例如 URLQueryAllowedCharacterSet)一起使用,因为它们都允许保留字符以未转义的形式传递.

See https://stackoverflow.com/a/35912606/1271826 for alternative percent-escaping options. But avoid using stringByAddingPercentEncodingWithAllowedCharacters with any of the existing character sets (e.g. URLQueryAllowedCharacterSet), because they all allow reserved characters to pass unescaped.

如果您真的希望服务器代码将其作为 x-www-form-urlencoded 请求中的数组接收,您可能需要:

If you really want this received as an array in an x-www-form-urlencoded request by your server code, you'd probably want:

var selectedStudentsArray = [String]()
for index in 0 ..< selectedStudents.count {
    selectedStudentsArray.append("selectedStudents[]=\(selectedStudents[index])")
}
let selectedStudentsString = selectedStudentsArray.joinWithSeparator("&")

这将产生:

selectedStudents[]=26&selectedStudents[]=25

这是在 x-www-form-urlencoded 请求中发送值数组的正确方法.

That's the right way to send an array of values in an x-www-form-urlencoded request.

您的 text 值也包含保留字符.你应该百分之百地转义这个(以及任何其他可能包含 a-z, A-Z 之外的字符的东西>、0-9-._~/?).同样,在执行这样的 x-www-form-urlencoded 请求时,所有保留字符都必须进行百分比转义.

Your text value includes reserved characters, too. You should be percent escaping this (and anything else that might include characters outside of a-z, A-Z, 0-9, and -, ., _, ~, /, and ?). Again, when doing x-www-form-urlencoded request like this, all reserved characters must be percent escaped.

您正在获取图像数组并构建 NSKeyedArchiver.就您的 Web 服务而言,这将是一个大的、不透明的 blob 对象.如果您的意图是将其视为服务器上的单个 blob,那很好,但是如果您希望从中提取图像,那么您的生活就会变得不必要地复杂.

You are taking your array of images and building a NSKeyedArchiver. This is going to be one big, opaque, blob object as far as your web service is concerned. If your intent is to treat this as a single blob on the server, that's fine, but if you were hoping to then extract the images out of that, you're making your life unnecessarily complicated.

您可以:

  • 分别对图像进行 Base-64 编码,然后使用我为 selectStudents 建议的相同格式,例如

  • Base-64 encode the images separately and then use the same format I suggested for selectStudents, e.g.

image[]=Bsa...JJH&image[]=5YJ...mVj

注意,您应该使用数据的原始内容(例如,直接从原始文件/资产中获取 NSData,完全避免 UIImage),或者,如果您真的需要通过 UIImage 来回传输它(如果你能阻止它,我会劝阻它),然后使用 UIImagePNGRepresentationUIImageJPEGRepresentationUIImage 创建一个新的 NSData.

Note, you should use the original contents of the data (e.g. get the NSData directly from the original file/asset, avoiding UIImage altogether) or, if you really need to round-trip it through a UIImage (which I'd discourage if you can prevent it), then use UIImagePNGRepresentation or UIImageJPEGRepresentation to create a new NSData from the UIImage.

您可能会考虑使用 multipart/form-data 请求,然后单个图像(同样,尽管有上述关于获取 NSData 的注释)可以单独存放.如果您执行正确的 multipart/form-data 请求,它也可以避免在任何地方进行任何百分比转义,也可以避免 base-64 编码(这使得传输比需要的大 33%)等

You might consider using a multipart/form-data request and then the individual images (again, with the aforementioned comment about getting the NSData notwithstanding) can be stored individually. If you do proper multipart/form-data request, it avoids needing to do any percent-escaping anywhere, too, avoids base-64 encoding (which makes the transmission 33% larger than it needs to be), etc.

归根结底,正确创建这些类型的请求非常非常复杂,除非你真的想解开所有这些特性,否则我真的鼓励你考虑 Alamofire,让您远离这些杂草.如果你真的觉得有必要重新发明轮子,我建议你单独研究这些主题,因为这对于一个问题来说太宽泛了.我上面的每一点可能都需要一个单独的问题.

Bottom line, properly creating these sorts of requests is very, very complicated, and unless you really want to unravel all of these idiosyncrasies, I'd really encourage you to consider Alamofire, which gets you out of these weeds. And if you truly feel compelled to reinvent the wheel, I'd suggest you research these topics individually, as this is far too broad for a single question. Each of my points above probably warrants a separate question.

这篇关于由 base64encodeString 组成的 NSMutableRequest 的主体在作为字符串发送时被截断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆