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

Posted

技术标签:

【中文标题】通过 API 将带有 Alamofire 的 STL 文件上传到 Octoprint【英文标题】:Uploading an STL file with Alamofire to Octoprint through API 【发布时间】:2019-08-22 22:40:50 【问题描述】:

我一直在尝试使用 Alamofire 在 swift ios 应用程序中创建一个将文件 (STL) 上传到 Octoprint API 的函数。我所有的其他 API 函数都运行良好,所以我假设我的上传问题与所需的多部分数据有关。我不断收到 403 错误。

我当前的代码:

func uploadFile(printer: Printers, localFileURL: URL, completion: @escaping (JSON) -> ()) 

        let url = printer._ipaddress! + "api/files/local"
        let key = printer._apikey!
        let boundary = "Boundary-\(UUID().uuidString)"
        let contentType = "multipart/form-data"
        let fileData = try! String(contentsOf: localFileURL).data(using: String.Encoding.utf8, allowLossyConversion: false)

        Alamofire.upload(
            multipartFormData:  (multipart) in
                multipart.boundary = boundary
                multipart.contentType = contentType
                multipart.append(key.data(using: String.Encoding.utf8, allowLossyConversion: false)!, withName: "X-Api-Key")
                multipart.append(fileData!, withName: "file", fileName: localFileURL.lastPathComponent, mimeType: "application/octet-stream")
        ,
            to: url,
            encodingCompletion:  encodingResult in
                switch encodingResult 
                case .success(let upload, _, _):
                    upload.responseJSON  response in
                        debugPrint(response)
                    
                case .failure(let encodingError):
                    print(encodingError)
                
        
        )
    

错误信息:

responseValidationFailed(reason: Alamofire.AFError.ResponseValidationFailureReason.unacceptableStatusCode(code: 403))
2019-08-22 18:34:51.120426-0400 iOSApp[32279:979456] [] nw_socket_handle_socket_event [C9:2] Socket SO_ERROR [54: Connection reset by peer]
[Request]: POST http://192.168.2.14/api/files/local
[Response]: <NSHTTPURLResponse: 0x600001f28fe0>  URL: http://192.168.2.14/api/files/local   Status Code: 400, Headers 
    "Content-Length" =     (
        73
    );
    "Content-Type" =     (
        "text/html; charset=UTF-8"
    );
    Date =     (
        "Thu, 22 Aug 2019 22:34:51 GMT"
    );
    "X-Robots-Tag" =     (
        "noindex, nofollow, noimageindex"
    );
 
[Data]: 73 bytes
[Result]: FAILURE: responseSerializationFailed(reason: Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(error: Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo=NSDebugDescription=Invalid value around character 0.))
[Timeline]: Timeline:  "Request Start Time": 588206091.090, "Initial Response Time": 588206091.092, "Request Completed Time": 588206091.125, "Serialization Completed Time": 588206091.125, "Latency": 0.002 secs, "Request Duration": 0.035 secs, "Serialization Duration": 0.000 secs, "Total Duration": 0.035 secs 

【问题讨论】:

如果您不断收到 403 状态码,为什么您发布的错误消息显示[Response]: &lt;NSHTTPURLResponse: 0x600001f28fe0&gt; URL: http://192.168.2.14/api/files/local Status Code: 400, Headers 1.是什么使以下成为 URL 对象?让 url = 打印机._ipaddress! + "api/files/local" 2. 您正在强制展开至少两个选项。你打算什么时候学习如何打开它们? 【参考方案1】:

我让它工作,发布代码以防它帮助其他人。这是我第一次使用多部分 POST,所以我只是错误地构建了正文和标题。使用 Postman 运行测试确实帮助我更好地理解了一点。

func uploadFile(printer: Printers, localFileURL: URL, completion: @escaping (JSON) -> ()) 

    let url = printer._ipaddress! + "api/files/local"
    let key = printer._apikey!
    let boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"
    let mimeType = "application/octet-stream"
    let fileData = try! String(contentsOf: localFileURL)

    let header = HTTPHeaders(dictionaryLiteral: ("X-Api-Key", key), ("content-type", "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW"))

    Alamofire.upload(
        multipartFormData:  (multipart) in
            multipart.append(boundary.data(using: String.Encoding.utf8)!, withName: "bounday")
            multipart.append(fileData.data(using: String.Encoding.utf8)!, withName: "file", fileName: localFileURL.lastPathComponent, mimeType: mimeType)
            multipart.append(boundary.data(using: String.Encoding.utf8)!, withName: "bounday")
            multipart.append("false".data(using: String.Encoding.utf8)!, withName: "select")
            multipart.append(boundary.data(using: String.Encoding.utf8)!, withName: "bounday")
            multipart.append("false".data(using: String.Encoding.utf8)!, withName: "print")
    ,
        to: url,
        headers: header,
        encodingCompletion:  encodingResult in
            switch encodingResult 
            case .success(let upload, _, _):
                upload.responseJSON  response in
                    debugPrint(response)
                
            case .failure(let encodingError):
                print(encodingError)
            
    
    )

【讨论】:

以上是关于通过 API 将带有 Alamofire 的 STL 文件上传到 Octoprint的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 RxSwift 和 Alamofire 使用分页?

带有 åäö(特殊字符)的 Alamofire GET 请求,无效 url

Alamofire 响应与请求不匹配

使用 Alamofire 调用带有 HTTP Header 和 Body 的 API

带有标头的 Alamofire 请求?

GoogleDrive + Alamofire:上传带有属性的文件