Alamofire 文件上传出现错误“JSON 文本未以数组或对象开头,并且允许未设置片段的选项”

Posted

技术标签:

【中文标题】Alamofire 文件上传出现错误“JSON 文本未以数组或对象开头,并且允许未设置片段的选项”【英文标题】:Alamofire file upload getting error "JSON text did not start with array or object and option to allow fragments not set" 【发布时间】:2018-01-12 06:36:05 【问题描述】:

下面是我的代码引用this question answer

func createRequest(ResumeID: String, CandidateID: String, MediaName: String, FileExtension : String, MediaType : String) throws -> URLRequest 

    let parameters = NSDictionary(objects: [ResumeID, CandidateID, MediaName, FileExtension,MediaType], forKeys: ["ResumeID" as NSCopying, "CandidateID" as NSCopying, "MediaName" as NSCopying, "FileExtension" as NSCopying, "MediaType" as NSCopying])

    let boundary = generateBoundaryString()

    let url = URL(string: "http://192.168.1.29/ColorsKit_New_Svr/WTCSvr.svc/WTCService?Id=6&SPName=Usp_RTN_IU_CandidateSubmissionResume")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

    let path1 = Bundle.main.path(forResource: "dummy-pdf_2", ofType: "pdf")!
    request.httpBody = try createBody(with: parameters as? [String : String], filePathKey: "MediaContent", paths: [path1], boundary: boundary)

    return request


private func createBody(with parameters: [String: String]?, filePathKey: String, paths: [String], boundary: String) throws -> Data 
    var body = Data()

    if parameters != nil 
        for (key, value) in parameters! 
            body.append("--\(boundary)\r\n")
            body.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
            body.append("\(value)\r\n")
        
    

    for path in paths 
        let url = URL(fileURLWithPath: path)
        let filename = url.lastPathComponent
        let data = try Data(contentsOf: url)
        let mimetype = mimeType(for: path)

        body.append("--\(boundary)\r\n")
        body.append("Content-Disposition: form-data; name=\"\(filePathKey)\"; filename=\"\(filename)\"\r\n")
        body.append("Content-Type: \(mimetype)\r\n\r\n")
        body.append(data)
        body.append("\r\n")
    

    body.append("--\(boundary)--\r\n")
    return body


func sendMultipartRequest() 
    let request: URLRequest

    do 
        request = try createRequest(ResumeID: "1", CandidateID: "1241124", MediaName: "dummy-pdf", FileExtension: "pdf", MediaType: "pdf")
     catch 
        print(error)
        return
    

    let task = URLSession.shared.dataTask(with: request)  data, response, error in
        guard error == nil else 
            // handle error here
            print(error!)
            return
        

        // if response was JSON, then parse it

        do                 
            let responseDictionary = try JSONSerialization.jsonObject(with: data!)
            print("success == \(responseDictionary)")

            // note, if you want to update the UI, make sure to dispatch that to the main queue, e.g.:
            //
            // DispatchQueue.main.async 
            //     // update your UI and model objects here
            // 
         catch 
            print(error)

            let responseString = String(data: data!, encoding: .utf8)
            print("responseString = \(String(describing: responseString))")
        
    
    task.resume()

我得到的回应是:

Error Domain=NSCocoaErrorDomain Code=3840 "JSON 文本没有开始 带有数组或对象以及允许未设置片段的选项。” UserInfo=NSDebugDescription=JSON 文本不是以数组开头或 允许未设置片段的对象和选项。 responseString = 可选(“未找到记录”)

这很奇怪,因为 Postman 给出了正确的响应。意味着仅代码中缺少某些内容:(

【问题讨论】:

在你的后端检查一次,它是一个有效的 JSON 这应该是有效的,因为我通过“邮递员”得到了完美的回应 post Man 给出正确答案,根据我们的编码级别,它会出现错误, 是的,我只是在说 顺便说一句,您的问题标题和标签说 Alamofire,但您是手动构建它(这比 Alamofire 工作量更大)。你要不要使用 Alamofire? 【参考方案1】:

使用 Alamofire

let upload_url = "your url"
let fieldName = "UploadedFile"
let mimeType = "plain/text"


Alamofire.upload(multipartFormData:  multipartFormData in

//you can add multiple file
        multipartFormData.append(fileData as Data, withName: fieldName, fileName: fileName, mimeType: mimeType)

    , to: upload_url, method: .post, headers: ["Authorization": "auth_token"],

       encodingCompletion:  encodingResult in
        switch encodingResult 
        case .success(let upload, _, _):
            upload.response  [weak self] response in
                guard let _ = self else 
                    return
                
                debugPrint(response)
            
        case .failure(let encodingError):
            debugPrint("uploaderService error:\(encodingError)")
        

    )

【讨论】:

【参考方案2】:

如下使用 JSONSerialization

if let responseDictionary = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? String 

...

【讨论】:

以上是关于Alamofire 文件上传出现错误“JSON 文本未以数组或对象开头,并且允许未设置片段的选项”的主要内容,如果未能解决你的问题,请参考以下文章

Alamofire 上传失败,文件超过 1MB

使用 Alamofire swift 4 上传文件

Alamofire(Swift 3):对成员“上传(..”)的模糊引用

如何使用 alamofire 和数组形式的参数上传图像

通过 API 将带有 Alamofire 的 STL 文件上传到 Octoprint

使用 Alamofire(多部分数据)上传带有额外参数的 .PDF 文件时出错