Получение ошибки при получении JSON после метода публикации в Swift

Я отправляю запрос POST на свой сервер, но получаю эту ошибку:

The given data was not valid JSON.",
underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840
"JSON text did not start with array or object and option to allow
 fragments not set."
UserInfo={NSDebugDescription=JSON text did not start with array
or object and option to allow fragments not set.})))

И это код, который я использую для отправки/получения данных:

func fetchDataWithParameters(){

    struct Response: Codable {
        let status: String?
        let error: String?
    }

    let decoder = JSONDecoder()
    HTTP.POST("somelinkhere", parameters: ["date": self.weekDays[self.itemSelectedIndex]]) { response in
        if let error = response.error {
            print("got an error: \(error)")
            return
        }
        do {
            let resp = try decoder.decode(Response.self, from: response.data)
            if let err = resp.error {
                print("got an error: \(err)")
            }
            if let status = resp.status {
                print("completed: \(status)")

            }
        } catch let error {
            print("decode json error: \(error)")
        }
    }
}

Используя свой терминал, я пытаюсь выполнить ручной POST-запрос и получаю следующее:

Admins-MacBook-Pro:hello-world admin$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" somelinkhere
HTTP/1.1 200 OK
Server: openresty/1.9.15.1
Date: Thu, 03 May 2018 23:42:04 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 39
Connection: keep-alive
X-Clacks-Overhead: GNU Terry Pratchett

"{\"name\": \"Timo\", \"age\": \"39\"}"

Это заставляет меня задаться вопросом, что единственная возможная ошибка может заключаться в том, как я декодирую JSON. Зачем еще это будет работать с терминалом? Любые идеи?

Как предложил @patru, я включил здесь печать:

catch let error {
    print(String(data:response.data, encoding: .utf8)!)
    print("decode json error: \(error)")
}

Это был результат:

"{\"name\": \"Mergim\", \"age\": \"39\"}"
decode json error: dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.})))

Кажется, что я получаю JSON, как и с завитком, но по какой-то причине Swift не видит его как действительный JSON? Вот как мой метод публикации выглядит в бэкэнде:

@app.route('/', methods=['GET', 'POST'])
def index():

    jsonData = {"name": "Timo", "age": "39"}
    jsonData1 = {"name": "Mergim", "age": "39"}

    if request.method=='GET':
        return json.dumps(jsonData)

    elif request.method=='POST':
        return json.dumps(jsonData1)

ИЗМЕНИТЬ

    jsonData = '{"name": "Timo", "age": "39"}'
    jsonData1 = '{"name": "Mergim", "age": "39"}'

изменился на:

    jsonData = {"name": "Timo", "age": "39"}
    jsonData1 = {"name": "Mergim", "age": "39"}

person EmbeddedOS    schedule 03.05.2018    source источник
comment
Учитывая ваш вывод curl, это должен быть действительный JSON, учитывая ваше сообщение об ошибке, похоже, что это не так. Трудно сказать, не видя, что вы фактически получаете. Пожалуйста, попробуйте распечатать print(String(data:response.data, encoding: .utf8)) и предоставьте нам результат, возможно, это поможет. (И, пожалуйста, сделайте это, отредактировав свой вопрос, поскольку вы можете видеть, что код имеет тенденцию выглядеть беспорядочно в (более ограниченных) комментариях.)   -  person Patru    schedule 04.05.2018
comment
Где в вашей команде curl вы передаете параметр даты, который вы передаете в своем коде?   -  person Mike Taverne    schedule 04.05.2018
comment
@MikeTaverne В данном случае это не имеет значения. Я просто использую любое значение, чтобы получить ответ. Реализация даты придет позже.   -  person EmbeddedOS    schedule 04.05.2018


Ответы (1)


Это тонко, но, хотите верьте, хотите нет, проблема на Сервере!

На самом деле ваш код выглядел ... немного не так, но все же вполне нормально, поэтому я запустил эту игровую площадку:

import Cocoa

let jsonData = "{\"name\": \"Mergim\", \"age\": \"39\"}".data(using: .utf8)!

struct Response: Codable {
    let status: String?
    let error: String?
}

struct NameAge: Codable {
    let name: String
    let age: String
}

do {
    let resp = try JSONDecoder().decode(Response.self, from: jsonData)
    print(resp)
    let na = try JSONDecoder().decode(NameAge.self, from: jsonData)
    print(na)
} catch {
    print(error)
}

print(String(data:jsonData, encoding: .utf8)!)

Поскольку ваша структура Response не совсем соответствует структуре ваших данных, я реализовал NameAge, чтобы получить что-то более подходящее. Тем не менее оба анализируют, хотя значение Response остается сомнительным. Я тоже был озадачен, пока не проверил ваше сообщение об ошибке: оно жалуется на первый символ в ваших данных! Наконец-то я добавил последнюю строчку в Playground и проблема стала ясна.

Вы предоставили своему серверу (думаю, он на рубине или что-то близкое к нему) действительный объект String, и он превратил его в соответствующий JSON, который по-прежнему представляет просто строку в JSON. Это объясняет двойные кавычки, которые у вас есть, а моя игровая площадка не производит. Вероятно, вам следует указать jsonData как Hash, и сервер правильно преобразует его (без двойных кавычек). По случайной причине JSONDecoder не хочет декодировать простую JSON-строку, но это то, за что я извиняюсь.

Кстати: вы, вероятно, захотите изменить тип age на Int, как только сможете правильно его передать.

person Patru    schedule 04.05.2018
comment
Принимая во внимание то, что вы сказали, я просто изменил способ создания своих строк на сервере. Проверьте редактирование, которое я сделал в коде сервера. Теперь я не получаю ошибок, но почему он не распечатывается как завершенный, мне удалось напечатать ответ, и он был правильным, но я хочу иметь возможность что-то делать, когда он достигает завершающей части запроса, а именно, если let status = resp.status ?? - person EmbeddedOS; 06.05.2018
comment
Я думал, что ясно дал понять это в своем коде: вы не сможете декодировать status и error из фрагмента JSON, который только содержит name и age. Пока вы определяете их как необязательные, ваш decode все еще будет работать, но ваш status всегда будет пустым. Вы должны иметь возможность получить некоторый HTTP-статус из объекта response, который вы получили методом HTTP.POST. Запустив мою игровую площадку, вы обнаружите, что вы можете только получить разумные значения из заданной строки, если вы decode NameAge, нет Response. - person Patru; 07.05.2018