使用Swift的URLRequest同时上传图片和其他参数

使用Swift的URLRequest同时上传图片和其他参数

有时候我们会有同时上传图片和其他参数(比如图片来源、名称等)的需求,这个时候一搬都会使用multipart/formdata形式上传,第三方库用多了,那如何用Swift原生代码实现类似Alamofire的MultipartFormData功能呢?


思路

  • 创建一个URLRequest,POST还是GET请随意
  • 将图片加入到请求体(httpbody)里
  • 将请求体(httpbody)里的除了图片的其他参数都带上boundary
  • 最后再加上结束的boundary终结这个httpbody
  • 使用URLSession的dataTask发起请求
  • 结束

code

import Foundation

// 声明一个闭包,之后使用的时候就可以使用回调
typealias postActionClosure = (_ data: Data, _ response: URLResponse) -> Void

class MultipartUpload {
    var myClosure: postActionClosure?
    func postAction(_ imageData: Data, url: NSURL, parameters: [String : Any], closure: @escaping postActionClosure) {
        // 函数指针赋值给myClosure闭包
        self.myClosure = closure
        // 创建一个起到分割作用的boundary
        let boundary = getRandomBoundary()
        // 创建一个网络请求对象
        let request = NSMutableURLRequest(url: url as URL)

        // 从这里开始构造请求体
        // 存放参数的数组,后续好转成字符串,也就是请求体
        let body  = NSMutableArray()
        // 拼接参数和boundary的临时变量
        var fileTmpStr = ""
        if parameters.count > 0 {
            //设置为POST请求
            request.httpMethod = "POST"
            request.setValue("multipart/form-data; boundary=----\(boundary)", forHTTPHeaderField: "Content-Type")
            //拆分字典,parameter是其中一项,将key与value变成字符串
            for parameter in parameters {
                // 将boundary和parameter组装在一起
                fileTmpStr = "------\(boundary)\r\nContent-Disposition: form-data; name=\"\(parameter.0)\"\r\n\r\n\(parameter.1)\r\n"
                body.add(fileTmpStr)
            }
            // 上传文件的文件名,按照需求起名字就好
            let filename = ""
            // 将文件名和boundary组装在一起
            fileTmpStr = "------\(boundary)\r\nContent-Disposition: form-data; name=\"picture\"; filename=\"\(filename)\"\r\n"
            body.add(fileTmpStr)
            // 文件类型是图片,png、jpeg随意
            fileTmpStr = "Content-Type: image/png\r\n\r\n"
            body.add(fileTmpStr)
            // 将body里的内容转成字符串
            let parameterStr = body.componentsJoined(by: "")
            // UTF8转码,防止汉字符号引起的非法网址
            var parameterData = parameterStr.data(using: String.Encoding.utf8)!
            // 将图片追加进parameterData
            parameterData.append(imageData)
            // 将boundary结束部分追加进parameterData
            parameterData.append("\r\n------\(boundary)--".data(using: String.Encoding.utf8)!)
            // 设置请求体
            request.httpBody = parameterData
            //默认session配置
            let config = URLSessionConfiguration.default
            let session = URLSession(configuration: config)
            //发起请求
            let dataTask = session.dataTask(with: request as URLRequest) { (data, response, error) in
                if data != nil {
                    if let closure = self.ocrClosure {
                        closure(data!, response!)
                    }
                }
            }
            //请求开始
            dataTask.resume()
        }
    }

    // MARK: - 获取boundary
    private func getRandomBoundary() -> String {
        // 这个Boundary是随机数
        return String(format: "WebKitFormBoundary%08x%08x", arc4random(), arc4random())
    }
}

使用

// closure很方便
MultipartUpload.init().postAction(imagePNG!, url: self.url!, parameters: paramDic) { (data, response) in
    print("-------post中")
    let jsonData:NSDictionary = try! JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! NSDictionary
    print("-------结果:\(jsonData)")
}

参考文章:
Swift 3 and iOS: Form data and multipart uploads with URLRequest
Alamofire/Source/MultipartFormData.swift

你可能感兴趣的:(swift,iOS,网络请求)