Кодирование строки запроса Alamofire искажает параметры JSON - PullRequest
0 голосов
/ 29 декабря 2018

Хорошо, идея такова:

  • для загрузки видеофайла в виде запроса из нескольких частей

  • установка токенов в качестве заголовка

  • тело должно быть закодировано как queryString

И для этого типа json все работает отлично:

{
  "description": "opi",
  "playerJersey": [
    {
      "playerId": "5c209d446ea7260b82fb0933",
      "playerJerseyColor": "Black"
    }
  ],
  "title": "nas",
  "playerList": [
    {
      "_id": "5c209d446ea7260b82fb0933"
    }
  ]
}

но, если есть большечем 1 игрок в данных, и JSON выглядит так:

{
  "description": "opi",
  "playerJersey": [
    {
      "playerId": "5c209d446ea7260b82fb0933",
      "playerJerseyColor": "Black"
    },
    {
      "playerId": "5c209d4c6ea7260b82fb0934",
      "playerJerseyColor": "Yellow"
    }
  ],
  "title": "nas",
  "playerList": [
    {
      "_id": "5c209d446ea7260b82fb0933"
    },
    {
      "_id": "5c209d4c6ea7260b82fb0934"
    }
  ]
}

Я перехватил запрос и распечатал URL-адрес и расшифровал его онлайн, и вот как он сформирован:

http://194.106.182.88:3000/video/upload/5c209d1a6ea7260b82fb0932?description=opi&playerJersey%5B%5D%5BplayerId%5D=5c209d446ea7260b82fb0933&playerJersey%5B%5D%5BplayerJerseyColor%5D=Black&playerJersey%5B%5D%5BplayerId%5D=5c209d4c6ea7260b82fb0934&playerJersey%5B%5D%5BplayerJerseyColor%5D=Yellow&playerList%5B%5D%5B_id%5D=5c209d446ea7260b82fb0933&playerList%5B%5D%5B_id%5D=5c209d4c6ea7260b82fb0934&title=nas

или немного украшенный и декодированный%:

http://194.106.182.88:3000/video/upload/5c209d1a6ea7260b82fb0932?description=opi
&playerJersey[]
          [playerId]=5c209d446ea7260b82fb0933
&playerJersey[]
          [playerJerseyColor]=Black
&playerJersey[]
          [playerId]=5c209d4c6ea7260b82fb0934
&playerJersey[]
          [playerJerseyColor]=Yellow
&playerList[]
          [_id]=5c209d446ea7260b82fb0933
&playerList[]
           [_id]=5c209d4c6ea7260b82fb0934
&title=nas

Что не кажется правильным (эти два последних _id должны быть их собственным отдельным словарем / json, и эта кодировка, кажется, объединяет их вместев одном playerList и ответ, который я получаю от сервера, снова связан с этим вопросом и выглядит следующим образом:

[Данные]: 701 байт [Результат]: УСПЕХ: {"статус": 500,"message": "Внутренняя ошибка сервера!", "error": {"errors": {"playerList": {"message": "Преобразование в массив не выполнено для оценкиe \ " [{_id: ['5c209d446ea7260b82fb0933', '5c209d4c6ea7260b82fb0934']}] \" at path \ "playerList \" "," name ":" CastError "," stringValue ":" \ "[{_id: ['5c209d446ea7260b82fb0933', '5c209d4c6ea7260b82fb0934']}] \ "", "kind": "Array", "value": [{"_ id": ["5c209d446ea7260b82fb0933d] b6fc09b) 5cf 5c6c6bc5f6ccf5ccf5c6cf5ccf5c6b6ccf5c6cf5ccf5ccf5b6c6b6b6ccf5ccf5c5c6b6cf5c6b6ccf5c6b5c6fc5f6cc5b5b6ccf5c6b5c6b6cc5f5c6cf5c6c5c6cf5c6c5c6cf5c6c6, 5, cc, 6, cc6, cc6, cc {5}путь ":" playerList "," reason ": {}}}," _ message ":" Ошибка проверки видео "," message ":" Ошибка проверки видео: playerList: Ошибка приведения к массиву для значения \ "[{_id: ['5c209d446ea7260b82fb0933', '5c209d4c6ea7260b82fb0934']}] \ "at path \" playerList \ "", "name": "ValidationError"}}

где я выделил эту строку:

[ { _id: [ '5c209d446ea7260b82fb0933', '5c209d4c6ea7260b82fb0934' ] } ]

и да, это не то, что я хотел отправить (посмотрите снова на пример json в начале)

Вот мой код.

func postRequestForVideoStreamUpload(_ videoUrl: String, _ videoTitle: String, _ videoDescription: String, _ players: [PlayerIDInput],_ jerseys: [PlayerJersey], _ accessToken: String? = nil, callback: @escaping (() -> Void)) {
        guard let userId = UserDefaults.standard.currentUserID() else { return }
        guard let streamUrl = URL(string: [API.baseUrl, API.videoUpload, userId].joined(separator: "/")) else { return }
        let fileUrl = URL(fileURLWithPath: videoUrl)

        let accessToken = UserDefaults.standard.accessToken()

        var request = URLRequest(url: streamUrl)
        var finalRequest: URLRequest?
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type");
        if let token = accessToken {
            request.setValue(token, forHTTPHeaderField: "x-access-token")
        }

        var playersArr: [[String : String]] = []
        for player in players {
            var tempDict = Dictionary<String, String>()
            tempDict["_id"] = player.playerId
            playersArr.append(tempDict)
        }

        var jerseyArr: [[String : String]] = []
        for jersey in jerseys {
            var tempDict = Dictionary<String, String>()
            tempDict["playerId"] = jersey.playerId
            tempDict["playerJerseyColor"] = jersey.playerJerseyColor
            jerseyArr.append(tempDict)
        }

        let parameters: [String : Any] = [
            "title": videoTitle,
            "description": videoDescription,
            "playerList": playersArr,
            "playerJersey": jerseyArr
            ]

        do {
            try finalRequest =  Alamofire.URLEncoding(destination: .queryString).encode(request, with: parameters)
        } catch let err {
            print(err)
            return
        }

        do {
            let fileData = try Data(contentsOf: fileUrl)

            Alamofire.upload(multipartFormData: { (multiPartFormData) in
                multiPartFormData.append(fileData, withName: "withNamePolje", fileName: "fileNamePolje", mimeType: "video/mp4")
            }, with: finalRequest!) { (result) in
                switch result {
                case .success(request: let upload, _,  _):
                    upload.responseString { response in
                        debugPrint(response)
                    }.uploadProgress { progress in // main queue by default
                        DispatchQueue.main.async {
                            print("Upload Progress: \(progress.fractionCompleted)")
                        }
                    }
                    upload.response { (response) in
                        callback()
                    }
                    return
                case .failure(let err):
                    print(err)
                }
            }
        } catch let err {
            print(err)
        }
    }

Некоторые извещи, которые я пробовал:

1) Бесчисленные способы создания оригинального словаря / JSON, прежде чем поместить его в качестве параметра в finalRequest.

2) Замена:

try finalRequest =  Alamofire.URLEncoding(destination: .queryString).encode(request, with: parameters)

с:

try finalRequest =  Alamofire.URLEncoding(destination: .queryString, arrayEncoding: .brackets).encode(request, with: parameters)

(пробовал оба .brackets & .noBrackets)

...