使用 Swift 5.0 将 UIImage 上传到 REST API

Uploading an UIImage to REST API with Swift 5.0

我可以使用 Postman 将图片发送(上传)到 REST API。但是我无法将带有 Swift 代码的图片发送(上传)到 REST API.

首先分享一下使用Postman的原始数据:

 POST http://testwlbyp.abc.com/ebys-servis-rest/ebys
 200
 583 ms
 POST /ebys-servis-rest/ebys HTTP/1.1
 Content-Type: application/x-www-form-urlencoded
 User-Agent: PostmanRuntime/7.25.0
 Accept: */*
 Cache-Control: no-cache
 Postman-Token: 888b7a05-e796-447f-9f6f-f3265bc38f3d
 Host: testwlbyp.abc.com
 Accept-Encoding: gzip, deflate, br
 Connection: keep-alive
 Cookie: JSESSIONID=tZXqTQrm8CHDiALd42cIWIiyVctFPSCJMKh-nxIyfqnVLu4CXChe!-1356762059
 Content-Length: 11450
 ----------------------------postman
 Content-Disposition: form-data; name="p_type"

 LOAD_DOC
 ----------------------------postman
 Content-Disposition: form-data; name="doc_no"

 20200006966
 ----------------------------postman
 Content-Disposition: form-data; name="token"

 4268260b012c51fe8b2d41fe4c48e289
 ----------------------------postman
 Content-Disposition: form-data; name="theme_no"

 63
 ----------------------------postman
 Content-Disposition: form-data; name="all_parameters"

 FILE_NAME='myTest.jpg'
 ----------------------------postman
 Content-Disposition: form-data; name="profile_no"

 A-S
 ----------------------------postman
 Content-Disposition: form-data; name="ss_no"

 M1997069
 ----------------------------postman
 Content-Disposition: form-data; name="user_agent"


 ----------------------------postman
 Content-Disposition: form-data; name="file"; filename="testpic.jpg"

 <myTest.jpg>
 ----------------------------postman--

这是回复:

 HTTP/1.1 200 OK
 Date: Thu, 25 Jun 2020 08:00:15 GMT
 Content-Length: 169
 Content-Type: application/json
 {
   "LOGID": 282659,
   "RESULTID": "20200006966",
   "FILESIZE": -1,
   "OPNAME": "LOAD_DOC",
   "ERRORCODE": 0,
   "ERRORMESSAGE": "success"
 }

这里是 Swift 代码;

 func uploadPicture(paramaterImage: UIImage, parameterDocNo: String, parameterToken: String, parameterSSNo: String)
    {
        print("LOG 01") // I SEE THIS LOG
    
    let fileName = "testImageName.jpg"
    let oall_param : String = "FILE?_NAME='\(fileName+".jpg")'"

    let url = URL(string: "http://testwlbyp.abc.com/ebys-servis-rest/ebys")
    var urlRequest = URLRequest(url: url!)
    urlRequest.httpMethod = "POST"
    
    print("LOG 02") // I SEE THIS LOG
    
    let image = paramaterImage
    let data = image.jpegData(compressionQuality: 0.7)!
    let qstr = String(decoding: data, as: UTF8.self)
    
    // 1
    urlRequest.addValue("LOAD_DOC", forHTTPHeaderField: "p_type")
    
    // 2
    urlRequest.addValue(parameterDocNo, forHTTPHeaderField: "doc_no")
    
    // 3
    urlRequest.addValue(parameterToken, forHTTPHeaderField: "token")
    
    // 4
    urlRequest.addValue("63123", forHTTPHeaderField: "theme_no")
    
    // 5
    urlRequest.addValue(oall_param, forHTTPHeaderField: "all_parameters")
    
    // 6
    urlRequest.addValue("A-S", forHTTPHeaderField: "profile_no")
    
    // 7
    urlRequest.addValue(parameterSSNo, forHTTPHeaderField: "ss_no")
    
    // 8
    urlRequest.addValue("", forHTTPHeaderField: "user_agent")
    
    // 9
    urlRequest.addValue(qstr, forHTTPHeaderField: "file")
    
    
    let boundary = "Boundary-\(UUID().uuidString)"
    urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
    
    print("LOG 03") // I SEE THIS LOG

    
    //create body
    let body = NSMutableData()
    
    //append first line
    let line1_boundryPrefix = "--\(boundary)\r\n"
    body.append(line1_boundryPrefix.data(
        using: String.Encoding.utf8,
        allowLossyConversion: false)!)
    
    //append second line
    let line2_parameter = "Content-Disposition: form-data; name=\"source\"; filename=\"" + fileName + "\"\r\n"
    body.append(line2_parameter.data(
        using: String.Encoding.utf8,
        allowLossyConversion: false)!)
    
    //append third line (mime type)
    let mimeType = "image/jpg"
    let line3_contentType = "Content-Type: \(mimeType)\r\n\r\n"
    body.append(line3_contentType.data(
        using: String.Encoding.utf8,
        allowLossyConversion: false)!)
    
    //append image data
    //line4
    body.append(data)
    
    
    let line5 = "\r\n"
    body.append(line5.data(
        using: String.Encoding.utf8,
        allowLossyConversion: false)!)
    
    
    let line6 = "--" + boundary + "--\r\n"
    body.append(line6.data(
        using: String.Encoding.utf8,
        allowLossyConversion: false)!)
    urlRequest.httpBody = body as Data
    urlRequest.setValue(String(body.length), forHTTPHeaderField: "Content-Length")
    
    URLSession.shared.dataTask(with: urlRequest) { (data, urlResponse, error) in
        //handle callback
        print("LOG 04, urlResponse: \(urlResponse)") // I DON'T SEE THIS LOG
    }
    
    print("LOG END") // I SEE THIS LOG
    
}

这是 Xcode 输出的结果 window:

LOG 01
LOG 02
LOG 03
LOG END

我没看到LOG04

我正在将 UIImage 参数(paramaterImage: UIImage)从下面的结构发送到 uploadPicture 方法:

import UIKit
struct MyMedia {
    let key: String
    let filename: String
    let data: Data?
    let mimeType: String
    
    init?(withImage image: UIImage, forKey key: String) {
        self.key = key
        self.mimeType = "image/jpeg"
        self.filename = "temppicname.jpg"
        self.data = image.jpegData(compressionQuality: 1)
    }
}

您必须对该任务调用 resume(),否则它不会启动:

let task = URLSession.shared.dataTask(with: urlRequest) { (data, urlResponse, error) in
    //handle callback
    print("LOG 04, urlResponse: \(urlResponse)") // I DON'T SEE THIS LOG
}
task.resume()

之后,您需要确保按照与邮递员相同的方式格式化请求,否则服务器将拒绝它。

我建议您使用 Charles 代理之类的东西来比较您的应用程序发送的内容与您在 Postman 中发送的内容。

乍一看,您似乎是在根据请求 headers 发送 p_type 等,但在 Postman 的示例中,这些值是表单的一部分。